blob: 2f4729b715a88ebabc3901c373568406ee26cdb6 [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
leng.fang32af9fc2024-06-13 11:22:15 +080069#include "aml-weston/aml-backend.h"
70
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050071static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -040072
Daniel Stone087ddf02017-02-14 17:51:30 +000073static void
Marius Vlade83e7502019-10-29 17:29:37 +020074drm_backend_create_faked_zpos(struct drm_backend *b)
75{
76 struct drm_plane *plane;
77 uint64_t zpos = 0ULL;
78 uint64_t zpos_min_primary;
79 uint64_t zpos_min_overlay;
80 uint64_t zpos_min_cursor;
81
82 zpos_min_primary = zpos;
83 wl_list_for_each(plane, &b->plane_list, link) {
84 /* if the property is there, bail out sooner */
85 if (plane->props[WDRM_PLANE_ZPOS].prop_id != 0)
86 return;
87
88 if (plane->type != WDRM_PLANE_TYPE_PRIMARY)
89 continue;
90 zpos++;
91 }
92
93 zpos_min_overlay = zpos;
94 wl_list_for_each(plane, &b->plane_list, link) {
95 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
96 continue;
97 zpos++;
98 }
99
100 zpos_min_cursor = zpos;
101 wl_list_for_each(plane, &b->plane_list, link) {
102 if (plane->type != WDRM_PLANE_TYPE_CURSOR)
103 continue;
104 zpos++;
105 }
106
107 drm_debug(b, "[drm-backend] zpos property not found. "
108 "Using invented immutable zpos values:\n");
109 /* assume that invented zpos values are immutable */
110 wl_list_for_each(plane, &b->plane_list, link) {
111 if (plane->type == WDRM_PLANE_TYPE_PRIMARY) {
112 plane->zpos_min = zpos_min_primary;
113 plane->zpos_max = zpos_min_primary;
114 } else if (plane->type == WDRM_PLANE_TYPE_OVERLAY) {
115 plane->zpos_min = zpos_min_overlay;
116 plane->zpos_max = zpos_min_overlay;
117 } else if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
118 plane->zpos_min = zpos_min_cursor;
119 plane->zpos_max = zpos_min_cursor;
120 }
121 drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
122 "zpos_max %"PRIu64"\n",
123 drm_output_get_plane_type_name(plane),
124 plane->plane_id, plane->zpos_min, plane->zpos_max);
125 }
126}
127
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000128static int
129pageflip_timeout(void *data) {
130 /*
131 * Our timer just went off, that means we're not receiving drm
132 * page flip events anymore for that output. Let's gracefully exit
133 * weston with a return value so devs can debug what's going on.
134 */
135 struct drm_output *output = data;
136 struct weston_compositor *compositor = output->base.compositor;
137
138 weston_log("Pageflip timeout reached on output %s, your "
139 "driver is probably buggy! Exiting.\n",
140 output->base.name);
141 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
142
143 return 0;
144}
145
146/* Creates the pageflip timer. Note that it isn't armed by default */
147static int
148drm_output_pageflip_timer_create(struct drm_output *output)
149{
150 struct wl_event_loop *loop = NULL;
151 struct weston_compositor *ec = output->base.compositor;
152
153 loop = wl_display_get_event_loop(ec->wl_display);
154 assert(loop);
155 output->pageflip_timer = wl_event_loop_add_timer(loop,
156 pageflip_timeout,
157 output);
158
159 if (output->pageflip_timer == NULL) {
Antonio Borneo39578632019-04-26 23:57:31 +0200160 weston_log("creating drm pageflip timer failed: %s\n",
161 strerror(errno));
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000162 return -1;
163 }
164
165 return 0;
166}
167
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000168static void
169drm_output_destroy(struct weston_output *output_base);
170
Daniel Stone5ff289a2017-10-07 12:59:02 +0100171/**
172 * Returns true if the plane can be used on the given output for its current
173 * repaint cycle.
174 */
Daniel Stonee404b722019-06-22 18:40:31 +0100175bool
Daniel Stone5ff289a2017-10-07 12:59:02 +0100176drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500177{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100178 assert(plane->state_cur);
179
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900180 if (output->virtual)
181 return false;
182
Daniel Stone5ff289a2017-10-07 12:59:02 +0100183 /* The plane still has a request not yet completed by the kernel. */
184 if (!plane->state_cur->complete)
185 return false;
186
187 /* The plane is still active on another output. */
leng.fang32af9fc2024-06-13 11:22:15 +0800188 if (plane->state_cur->output && plane->state_cur->output != output) {
189 //plane->state_cur->output = output;
190 //return false;
191 }
Daniel Stone5ff289a2017-10-07 12:59:02 +0100192 /* Check whether the plane can be used with this CRTC; possible_crtcs
193 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300194 return !!(plane->possible_crtcs & (1 << output->crtc->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500195}
196
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300197struct drm_crtc *
198drm_crtc_find(struct drm_backend *b, uint32_t crtc_id)
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000199{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300200 struct drm_crtc *crtc;
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000201
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300202 wl_list_for_each(crtc, &b->crtc_list, link) {
203 if (crtc->crtc_id == crtc_id)
204 return crtc;
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000205 }
206
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000207 return NULL;
208}
209
Daniel Stone4c2fc702019-06-18 11:12:07 +0100210struct drm_head *
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300211drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
212{
213 struct weston_head *base;
214 struct drm_head *head;
215
216 wl_list_for_each(base,
217 &backend->compositor->head_list, compositor_link) {
218 head = to_drm_head(base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300219 if (head->connector.connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300220 return head;
221 }
222
223 return NULL;
224}
225
Leandro Ribeiro96bef052020-09-09 15:23:49 -0300226static struct drm_writeback *
227drm_writeback_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
228{
229 struct drm_writeback *writeback;
230
231 wl_list_for_each(writeback, &backend->writeback_connector_list, link) {
232 if (writeback->connector.connector_id == connector_id)
233 return writeback;
234 }
235
236 return NULL;
237}
238
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000239/**
Daniel Stonea08512f2016-11-08 17:46:10 +0000240 * Get output state to disable output
241 *
242 * Returns a pointer to an output_state object which can be used to disable
243 * an output (e.g. DPMS off).
244 *
245 * @param pending_state The pending state object owning this update
246 * @param output The output to disable
247 * @returns A drm_output_state to disable the output
248 */
249static struct drm_output_state *
250drm_output_get_disable_state(struct drm_pending_state *pending_state,
251 struct drm_output *output)
252{
253 struct drm_output_state *output_state;
254
255 output_state = drm_output_state_duplicate(output->state_cur,
256 pending_state,
257 DRM_OUTPUT_STATE_CLEAR_PLANES);
258 output_state->dpms = WESTON_DPMS_OFF;
259
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530260 output_state->protection = WESTON_HDCP_DISABLE;
261
Daniel Stonea08512f2016-11-08 17:46:10 +0000262 return output_state;
263}
264
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000265
266/**
267 * Mark a drm_output_state (the output's last state) as complete. This handles
268 * any post-completion actions such as updating the repaint timer, disabling the
269 * output, and finally freeing the state.
270 */
Daniel Stone4c2fc702019-06-18 11:12:07 +0100271void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000272drm_output_update_complete(struct drm_output *output, uint32_t flags,
273 unsigned int sec, unsigned int usec)
274{
Daniel Stonea08512f2016-11-08 17:46:10 +0000275 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +0000276 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000277 struct timespec ts;
278
279 /* Stop the pageflip timer instead of rearming it here */
280 if (output->pageflip_timer)
281 wl_event_source_timer_update(output->pageflip_timer, 0);
282
Daniel Stonebc15f682016-11-14 16:57:01 +0000283 wl_list_for_each(ps, &output->state_cur->plane_list, link)
284 ps->complete = true;
285
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000286 drm_output_state_free(output->state_last);
287 output->state_last = NULL;
limin.tianbf71b4c2024-08-27 09:09:34 +0000288 drm_send_video_display_time(output->state_cur, sec, usec);
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000289
290 if (output->destroy_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100291 output->destroy_pending = false;
292 output->disable_pending = false;
293 output->dpms_off_pending = false;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000294 drm_output_destroy(&output->base);
295 return;
296 } else if (output->disable_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100297 output->disable_pending = false;
298 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +0000299 weston_output_disable(&output->base);
300 return;
301 } else if (output->dpms_off_pending) {
302 struct drm_pending_state *pending = drm_pending_state_alloc(b);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100303 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +0000304 drm_output_get_disable_state(pending, output);
305 drm_pending_state_apply_sync(pending);
Michael Olbrichd70e7122020-08-06 09:57:54 +0200306 }
307 if (output->state_cur->dpms == WESTON_DPMS_OFF &&
308 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
Daniel Stonea08512f2016-11-08 17:46:10 +0000309 /* DPMS can happen to us either in the middle of a repaint
310 * cycle (when we have painted fresh content, only to throw it
311 * away for DPMS off), or at any other random point. If the
312 * latter is true, then we cannot go through finish_frame,
313 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000314 return;
315 }
316
317 ts.tv_sec = sec;
318 ts.tv_nsec = usec * 1000;
Derek Foreman74bdb352021-07-29 09:02:04 -0500319
limin.tianaaaff782024-12-20 09:49:25 +0000320 if (output->state_cur->dpms != WESTON_DPMS_OFF) {
Derek Foreman74bdb352021-07-29 09:02:04 -0500321 weston_output_finish_frame(&output->base, &ts, flags);
limin.tianaaaff782024-12-20 09:49:25 +0000322 } else {
Derek Foreman74bdb352021-07-29 09:02:04 -0500323 weston_output_finish_frame(&output->base, NULL,
324 WP_PRESENTATION_FEEDBACK_INVALID);
limin.tianaaaff782024-12-20 09:49:25 +0000325 }
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000326
327 /* We can't call this from frame_notify, because the output's
328 * repaint needed flag is cleared just after that */
329 if (output->recorder)
330 weston_output_schedule_repaint(&output->base);
331}
332
Daniel Stone95d48a22017-04-04 17:54:30 +0100333static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000334drm_output_render_pixman(struct drm_output_state *state,
335 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200336{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000337 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200338 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200339
340 output->current_image ^= 1;
341
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200342 pixman_renderer_output_set_buffer(&output->base,
343 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200344 pixman_renderer_output_set_hw_extra_damage(&output->base,
345 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200346
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200347 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200348
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200349 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +0100350
351 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200352}
353
Stefan Agner3654c672019-07-09 00:50:30 +0200354void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000355drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200356{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000357 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300358 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +0000359 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +0000360 struct drm_plane *scanout_plane = output->scanout_plane;
Scott Anderson15c603c2020-06-02 17:39:43 +1200361 struct drm_property_info *damage_info =
362 &scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
Armin Krezović545dba62016-08-05 15:54:18 +0200363 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +0100364 struct drm_fb *fb;
Scott Anderson15c603c2020-06-02 17:39:43 +1200365 pixman_region32_t scanout_damage;
366 pixman_box32_t *rects;
367 int n_rects;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200368
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100369 /* If we already have a client buffer promoted to scanout, then we don't
370 * want to render. */
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300371 scanout_state = drm_output_state_get_plane(state, scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +0000372 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100373 return;
374
Daniel Stone98d75e12020-03-06 11:03:14 +0000375 /*
376 * If we don't have any damage on the primary plane, and we already
377 * have a renderer buffer active, we can reuse it; else we pass
378 * the damaged region into the renderer to re-render the affected
Pekka Paalanen7f1a1132020-12-07 14:59:44 +0200379 * area. But, we still have to call the renderer anyway if any screen
380 * capture is pending, otherwise the capture will not complete.
Daniel Stone98d75e12020-03-06 11:03:14 +0000381 */
Daniel Stonee95169b2016-11-14 17:46:59 +0000382 if (!pixman_region32_not_empty(damage) &&
Pekka Paalanen7f1a1132020-12-07 14:59:44 +0200383 wl_list_empty(&output->base.frame_signal.listener_list) &&
Daniel Stonee95169b2016-11-14 17:46:59 +0000384 scanout_plane->state_cur->fb &&
385 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
Daniel Stone98d75e12020-03-06 11:03:14 +0000386 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
Daniel Stonee95169b2016-11-14 17:46:59 +0000387 fb = drm_fb_ref(scanout_plane->state_cur->fb);
388 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000389 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000390 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000391 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000392 }
Daniel Stone95d48a22017-04-04 17:54:30 +0100393
Daniel Stonee2e80132018-01-16 15:37:33 +0000394 if (!fb) {
395 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +0100396 return;
Daniel Stonee2e80132018-01-16 15:37:33 +0000397 }
398
399 scanout_state->fb = fb;
400 scanout_state->output = output;
401
402 scanout_state->src_x = 0;
403 scanout_state->src_y = 0;
Daniel Stonef9a61622020-03-06 11:07:15 +0000404 scanout_state->src_w = fb->width << 16;
405 scanout_state->src_h = fb->height << 16;
Daniel Stonee2e80132018-01-16 15:37:33 +0000406
407 scanout_state->dest_x = 0;
408 scanout_state->dest_y = 0;
Daniel Stonef9a61622020-03-06 11:07:15 +0000409 scanout_state->dest_w = output->base.current_mode->width;
410 scanout_state->dest_h = output->base.current_mode->height;
Daniel Stonee2e80132018-01-16 15:37:33 +0000411
leng.fang32af9fc2024-06-13 11:22:15 +0800412 drm_output_render_aml_config(output, scanout_state);
413
Scott Anderson15c603c2020-06-02 17:39:43 +1200414 pixman_region32_subtract(&c->primary_plane.damage,
415 &c->primary_plane.damage, damage);
416
417 /* Don't bother calculating plane damage if the plane doesn't support it */
418 if (damage_info->prop_id == 0)
419 return;
420
421 pixman_region32_init(&scanout_damage);
422 pixman_region32_copy(&scanout_damage, damage);
423
Deepak Rawat46a1c722018-07-24 14:13:34 -0700424 if (output->base.zoom.active) {
Derek Foremandb7e85d2022-01-20 10:27:17 -0600425 pixman_region32_t clip;
426
Scott Anderson15c603c2020-06-02 17:39:43 +1200427 weston_matrix_transform_region(&scanout_damage,
Deepak Rawat46a1c722018-07-24 14:13:34 -0700428 &output->base.matrix,
Scott Anderson15c603c2020-06-02 17:39:43 +1200429 &scanout_damage);
Derek Foremandb7e85d2022-01-20 10:27:17 -0600430 pixman_region32_init_rect(&clip, 0, 0,
431 output->base.width,
432 output->base.height);
433 pixman_region32_intersect(&scanout_damage, &scanout_damage, &clip);
434 pixman_region32_fini(&clip);
Deepak Rawat46a1c722018-07-24 14:13:34 -0700435 } else {
Scott Anderson15c603c2020-06-02 17:39:43 +1200436 pixman_region32_translate(&scanout_damage,
Deepak Rawat46a1c722018-07-24 14:13:34 -0700437 -output->base.x, -output->base.y);
438 weston_transformed_region(output->base.width,
439 output->base.height,
440 output->base.transform,
441 output->base.current_scale,
Scott Anderson15c603c2020-06-02 17:39:43 +1200442 &scanout_damage,
443 &scanout_damage);
Deepak Rawat46a1c722018-07-24 14:13:34 -0700444 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200445
Scott Anderson15c603c2020-06-02 17:39:43 +1200446 assert(scanout_state->damage_blob_id == 0);
447
448 rects = pixman_region32_rectangles(&scanout_damage, &n_rects);
449
450 /*
451 * If this function fails, the blob id should still be 0.
452 * This tells the kernel there is no damage information, which means
453 * that it will consider the whole plane damaged. While this may
454 * affect efficiency, it should still produce correct results.
455 */
456 drmModeCreatePropertyBlob(b->drm.fd, rects,
457 sizeof(*rects) * n_rects,
458 &scanout_state->damage_blob_id);
459
460 pixman_region32_fini(&scanout_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200461}
462
Daniel Stonea08512f2016-11-08 17:46:10 +0000463static int
464drm_output_repaint(struct weston_output *output_base,
465 pixman_region32_t *damage,
466 void *repaint_data)
467{
468 struct drm_pending_state *pending_state = repaint_data;
469 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +0000470 struct drm_output_state *state = NULL;
471 struct drm_plane_state *scanout_state;
472
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900473 assert(!output->virtual);
474
Daniel Stonea08512f2016-11-08 17:46:10 +0000475 if (output->disable_pending || output->destroy_pending)
476 goto err;
477
478 assert(!output->state_last);
479
480 /* If planes have been disabled in the core, we might not have
481 * hit assign_planes at all, so might not have valid output state
482 * here. */
483 state = drm_pending_state_get_output(pending_state, output);
484 if (!state)
485 state = drm_output_state_duplicate(output->state_cur,
486 pending_state,
487 DRM_OUTPUT_STATE_CLEAR_PLANES);
488 state->dpms = WESTON_DPMS_ON;
489
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530490 if (output_base->allow_protection)
491 state->protection = output_base->desired_protection;
492 else
493 state->protection = WESTON_HDCP_DISABLE;
494
Daniel Stonea08512f2016-11-08 17:46:10 +0000495 drm_output_render(state, damage);
496 scanout_state = drm_output_state_get_plane(state,
497 output->scanout_plane);
498 if (!scanout_state || !scanout_state->fb)
499 goto err;
500
Daniel Stonea08512f2016-11-08 17:46:10 +0000501 return 0;
502
503err:
504 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +0200505 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400506}
507
Daniel Stone4c2fc702019-06-18 11:12:07 +0100508/* Determine the type of vblank synchronization to use for the output.
509 *
510 * The pipe parameter indicates which CRTC is in use. Knowing this, we
511 * can determine which vblank sequence type to use for it. Traditional
512 * cards had only two CRTCs, with CRTC 0 using no special flags, and
513 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
514 * parameter indicates this.
515 *
516 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
517 * 0-31. If this is non-zero it indicates we're dealing with a
518 * multi-gpu situation and we need to calculate the vblank sync
519 * using DRM_BLANK_HIGH_CRTC_MASK.
520 */
521static unsigned int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300522drm_waitvblank_pipe(struct drm_crtc *crtc)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100523{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300524 if (crtc->pipe > 1)
525 return (crtc->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
Daniel Stone4c2fc702019-06-18 11:12:07 +0100526 DRM_VBLANK_HIGH_CRTC_MASK;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300527 else if (crtc->pipe > 0)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100528 return DRM_VBLANK_SECONDARY;
529 else
530 return 0;
531}
532
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200533static int
Jonas Ådahle5a12252013-04-05 23:07:11 +0200534drm_output_start_repaint_loop(struct weston_output *output_base)
535{
Armin Krezović545dba62016-08-05 15:54:18 +0200536 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +0000537 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +0000538 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +0200539 struct drm_backend *backend =
540 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200541 struct timespec ts, tnow;
542 struct timespec vbl2now;
543 int64_t refresh_nsec;
544 int ret;
545 drmVBlank vbl = {
546 .request.type = DRM_VBLANK_RELATIVE,
547 .request.sequence = 0,
548 .request.signal = 0,
549 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300550
limin.tianaaaff782024-12-20 09:49:25 +0000551 weston_log("disable_pending:%d destroy_pending:%d fb%p state_invalid:%d hdmitx_hdcppwr:%d display_enable:%d\n",
552 output->disable_pending, output->destroy_pending, scanout_plane->state_cur->fb,
553 backend->state_invalid, backend->hdmitx_hdcppwr, backend->display_enable);
554
555 if (output->disable_pending || output->destroy_pending )
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200556 return 0;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800557
limin.tianaaaff782024-12-20 09:49:25 +0000558 if (!backend->display_enable) {
559 weston_log("\n :%s %d hdmitx_hdcppwr:%d display_enable:%d REPAINT_NOT_SCHEDULED\n",__FUNCTION__,__LINE__,
560 backend->hdmitx_hdcppwr, backend->display_enable);
561 output_base->repaint_status = REPAINT_NOT_SCHEDULED;
562 return 0;
563 }
564
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300565 if (!scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300566 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200567 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300568 }
569
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300570 /* Need to smash all state in from scratch; current timings might not
571 * be what we want, page flip might not work, etc.
572 */
Daniel Stone6020f472018-02-05 15:46:20 +0000573 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300574 goto finish_frame;
575
Daniel Stonee2e80132018-01-16 15:37:33 +0000576 assert(scanout_plane->state_cur->output == output);
577
Mario Kleinerf507ec32015-06-21 21:25:14 +0200578 /* Try to get current msc and timestamp via instant query */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300579 vbl.request.type |= drm_waitvblank_pipe(output->crtc);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200580 ret = drmWaitVBlank(backend->drm.fd, &vbl);
581
582 /* Error ret or zero timestamp means failure to get valid timestamp */
583 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
584 ts.tv_sec = vbl.reply.tval_sec;
585 ts.tv_nsec = vbl.reply.tval_usec * 1000;
586
587 /* Valid timestamp for most recent vblank - not stale?
588 * Stale ts could happen on Linux 3.17+, so make sure it
589 * is not older than 1 refresh duration since now.
590 */
591 weston_compositor_read_presentation_clock(backend->compositor,
592 &tnow);
593 timespec_sub(&vbl2now, &tnow, &ts);
594 refresh_nsec =
595 millihz_to_nsec(output->base.current_mode->refresh);
596 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
597 drm_output_update_msc(output, vbl.reply.sequence);
598 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200599 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200600 return 0;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200601 }
602 }
603
604 /* Immediate query didn't provide valid timestamp.
605 * Use pageflip fallback.
606 */
Jonas Ådahle5a12252013-04-05 23:07:11 +0200607
Daniel Stone205c0a02017-04-04 17:54:33 +0100608 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000609 assert(!output->state_last);
610
611 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +0000612 drm_output_state_duplicate(output->state_cur, pending_state,
613 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +0100614
Daniel Stone8747f952016-11-29 20:17:32 +0000615 ret = drm_pending_state_apply(pending_state);
616 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200617 weston_log("applying repaint-start state failed: %s\n",
618 strerror(errno));
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200619 if (ret == -EACCES)
620 return -1;
David Herrmann3c688c52013-10-22 17:11:25 +0200621 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200622 }
David Herrmann3c688c52013-10-22 17:11:25 +0200623
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200624 return 0;
David Herrmann3c688c52013-10-22 17:11:25 +0200625
626finish_frame:
627 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +0000628 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200629 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200630 return 0;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200631}
632
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000633/**
634 * Begin a new repaint cycle
635 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000636 * Called by the core compositor at the beginning of a repaint cycle. Creates
637 * a new pending_state structure to own any output state created by individual
638 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000639 */
640static void *
641drm_repaint_begin(struct weston_compositor *compositor)
642{
643 struct drm_backend *b = to_drm_backend(compositor);
644 struct drm_pending_state *ret;
645
646 ret = drm_pending_state_alloc(b);
647 b->repaint_data = ret;
648
Marius Vlad7e4db952019-04-17 13:47:06 +0300649 if (weston_log_scope_is_enabled(b->debug)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100650 char *dbg = weston_compositor_print_scene_graph(compositor);
651 drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
652 ret);
653 drm_debug(b, "%s", dbg);
654 free(dbg);
655 }
656
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000657 return ret;
658}
659
660/**
661 * Flush a repaint set
662 *
663 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000664 * and should be flushed. Frees the pending state, transitioning ownership
665 * of the output state from the pending state, to the update itself. When
666 * the update completes (see drm_output_update_complete), the output
667 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000668 */
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200669static int
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000670drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
671{
672 struct drm_backend *b = to_drm_backend(compositor);
673 struct drm_pending_state *pending_state = repaint_data;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200674 int ret;
Daniel Stone6020f472018-02-05 15:46:20 +0000675
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200676 ret = drm_pending_state_apply(pending_state);
677 if (ret != 0)
678 weston_log("repaint-flush failed: %s\n", strerror(errno));
679
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100680 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000681 b->repaint_data = NULL;
leng.fang32af9fc2024-06-13 11:22:15 +0800682#ifdef ENABLE_DRM_HELP
683 help_do_repaint_cycle_completed();
684#endif
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200685
686 return (ret == -EACCES) ? -1 : 0;
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000687}
688
689/**
690 * Cancel a repaint set
691 *
692 * Called by the core compositor when a repaint has finished, so the data
693 * held across the repaint cycle should be discarded.
694 */
695static void
696drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
697{
698 struct drm_backend *b = to_drm_backend(compositor);
699 struct drm_pending_state *pending_state = repaint_data;
700
701 drm_pending_state_free(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100702 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000703 b->repaint_data = NULL;
704}
705
Alex Wub7b8bda2012-04-17 17:20:48 +0800706static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300707drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +0000708static void
709drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200710
711static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800712drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
713{
Daniel Stone02d487a2017-10-07 14:01:45 +0100714 struct drm_output *output = to_drm_output(output_base);
715 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stonefbe6c1d2019-06-17 16:04:26 +0100716 struct drm_mode *drm_mode = drm_output_choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +0800717
718 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +0100719 weston_log("%s: invalid resolution %dx%d\n",
720 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800721 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200722 }
723
limin.tianc616dad2024-07-15 11:35:38 +0000724 if (&drm_mode->base == output->base.current_mode) {
725 weston_log("\n drm_output_switch_mode same mode return \n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800726 return 0;
limin.tianc616dad2024-07-15 11:35:38 +0000727 }
Hardeningff39efa2013-09-18 23:56:35 +0200728 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800729
leng.fang32af9fc2024-06-13 11:22:15 +0800730 drm_switch_mode_aml_config_ui_size(output, output_base, drm_mode);
731
Hardeningff39efa2013-09-18 23:56:35 +0200732 output->base.current_mode = &drm_mode->base;
733 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800734 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
735
leng.fang32af9fc2024-06-13 11:22:15 +0800736 drm_switch_mode_aml_config_help(output, output_base, drm_mode);
737
Daniel Stonef30a18c2017-04-04 17:54:31 +0100738 /* XXX: This drops our current buffer too early, before we've started
739 * displaying it. Ideally this should be much more atomic and
740 * integrated with a full repaint cycle, rather than doing a
741 * sledgehammer modeswitch first, and only later showing new
742 * content.
743 */
Daniel Stone6020f472018-02-05 15:46:20 +0000744 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +0800745
leng.fang32af9fc2024-06-13 11:22:15 +0800746 b->allow_modeset = true;
747#ifdef MESON_DRM_FIX_UI_SIZE
748 // fixed ui mode needn't reset egl.
749 return 0;
750#endif
751
Giulio Camuffo954f1832014-10-11 18:27:30 +0300752 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200753 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300754 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200755 weston_log("failed to init output pixman state with "
756 "new mode\n");
757 return -1;
758 }
759 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +0000760 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300761 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200762 weston_log("failed to init output egl state with "
763 "new mode");
764 return -1;
765 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200766 }
767
Alex Wub7b8bda2012-04-17 17:20:48 +0800768 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800769}
770
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200771static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300772init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200773{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300774 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200775}
776
Pekka Paalanen7b36b422014-06-04 14:00:53 +0300777/**
Pekka Paalanenec272712014-06-05 11:22:25 +0300778 * Create a drm_plane for a hardware plane
779 *
780 * Creates one drm_plane structure for a hardware plane, and initialises its
781 * properties and formats.
782 *
783 * This function does not add the plane to the list of usable planes in Weston
784 * itself; the caller is responsible for this.
785 *
786 * Call drm_plane_destroy to clean up the plane.
787 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100788 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +0300789 * @param b DRM compositor backend
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300790 * @param kplane DRM plane to create
Pekka Paalanenec272712014-06-05 11:22:25 +0300791 */
792static struct drm_plane *
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300793drm_plane_create(struct drm_backend *b, const drmModePlane *kplane)
Pekka Paalanenec272712014-06-05 11:22:25 +0300794{
795 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100796 drmModeObjectProperties *props;
Marius Vladcdd6fa22019-08-29 20:42:00 +0300797 uint64_t *zpos_range_values;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100798
Scott Anderson74663092021-02-01 15:46:33 -0300799 plane = zalloc(sizeof(*plane));
Pekka Paalanenec272712014-06-05 11:22:25 +0300800 if (!plane) {
801 weston_log("%s: out of memory\n", __func__);
802 return NULL;
803 }
804
805 plane->backend = b;
Daniel Stone57d609a2021-11-16 18:56:09 +0000806 plane->plane_idx = b->next_plane_idx++;
Daniel Stonebc15f682016-11-14 16:57:01 +0000807 plane->state_cur = drm_plane_state_alloc(NULL, plane);
808 plane->state_cur->complete = true;
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300809 plane->possible_crtcs = kplane->possible_crtcs;
810 plane->plane_id = kplane->plane_id;
Pekka Paalanenec272712014-06-05 11:22:25 +0300811
Scott Anderson74663092021-02-01 15:46:33 -0300812 weston_drm_format_array_init(&plane->formats);
813
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300814 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
815 DRM_MODE_OBJECT_PLANE);
816 if (!props) {
817 weston_log("couldn't get plane properties\n");
818 goto err;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100819 }
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300820
821 drm_property_info_populate(b, plane_props, plane->props,
822 WDRM_PLANE__COUNT, props);
823 plane->type =
824 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
825 props,
826 WDRM_PLANE_TYPE__COUNT);
827
828 zpos_range_values =
829 drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
830 props);
831
832 if (zpos_range_values) {
833 plane->zpos_min = zpos_range_values[0];
834 plane->zpos_max = zpos_range_values[1];
835 } else {
Marius Vladcdd6fa22019-08-29 20:42:00 +0300836 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300837 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100838 }
839
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300840 if (drm_plane_populate_formats(plane, kplane, props,
841 b->fb_modifiers) < 0) {
842 drmModeFreeObjectProperties(props);
843 goto err;
844 }
845
846 drmModeFreeObjectProperties(props);
847
Daniel Stone2ba17f42015-05-19 20:02:41 +0100848 if (plane->type == WDRM_PLANE_TYPE__COUNT)
849 goto err_props;
850
Pekka Paalanenec272712014-06-05 11:22:25 +0300851 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +0100852 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +0300853
854 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100855
856err_props:
857 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
858err:
Scott Anderson74663092021-02-01 15:46:33 -0300859 weston_drm_format_array_fini(&plane->formats);
Daniel Stone2ba17f42015-05-19 20:02:41 +0100860 drm_plane_state_free(plane->state_cur, true);
861 free(plane);
862 return NULL;
863}
864
865/**
866 * Find, or create, a special-purpose plane
867 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100868 * @param b DRM backend
869 * @param output Output to use for plane
870 * @param type Type of plane
871 */
872static struct drm_plane *
873drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
874 enum wdrm_plane_type type)
875{
876 struct drm_plane *plane;
877
Daniel Stone2ba17f42015-05-19 20:02:41 +0100878 wl_list_for_each(plane, &b->plane_list, link) {
879 struct drm_output *tmp;
880 bool found_elsewhere = false;
881
882 if (plane->type != type)
883 continue;
884 if (!drm_plane_is_available(plane, output))
885 continue;
886
887 /* On some platforms, primary/cursor planes can roam
888 * between different CRTCs, so make sure we don't claim the
889 * same plane for two outputs. */
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300890 wl_list_for_each(tmp, &b->compositor->output_list, base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +0000891 if (tmp->cursor_plane == plane ||
892 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +0100893 found_elsewhere = true;
894 break;
895 }
896 }
897
898 if (found_elsewhere)
899 continue;
900
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300901 plane->possible_crtcs = (1 << output->crtc->pipe);
Daniel Stone2ba17f42015-05-19 20:02:41 +0100902 return plane;
903 }
904
905 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +0300906}
907
908/**
909 * Destroy one DRM plane
910 *
911 * Destroy a DRM plane, removing it from screen and releasing its retained
912 * buffers in the process. The counterpart to drm_plane_create.
913 *
914 * @param plane Plane to deallocate (will be freed)
915 */
916static void
917drm_plane_destroy(struct drm_plane *plane)
918{
Daniel Stone2ba17f42015-05-19 20:02:41 +0100919 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
920 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
921 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +0000922 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100923 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +0300924 weston_plane_release(&plane->base);
Scott Anderson74663092021-02-01 15:46:33 -0300925 weston_drm_format_array_fini(&plane->formats);
Pekka Paalanenec272712014-06-05 11:22:25 +0300926 wl_list_remove(&plane->link);
927 free(plane);
928}
929
930/**
931 * Initialise sprites (overlay planes)
932 *
933 * Walk the list of provided DRM planes, and add overlay planes.
934 *
935 * Call destroy_sprites to free these planes.
936 *
937 * @param b DRM compositor backend
938 */
939static void
940create_sprites(struct drm_backend *b)
941{
942 drmModePlaneRes *kplane_res;
943 drmModePlane *kplane;
944 struct drm_plane *drm_plane;
945 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +0300946 kplane_res = drmModeGetPlaneResources(b->drm.fd);
947 if (!kplane_res) {
948 weston_log("failed to get plane resources: %s\n",
949 strerror(errno));
950 return;
951 }
leng.fang32af9fc2024-06-13 11:22:15 +0800952 for (i = kplane_res->count_planes; i >0; i--) {
953 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i-1]);
Pekka Paalanenec272712014-06-05 11:22:25 +0300954
Pekka Paalanenec272712014-06-05 11:22:25 +0300955 if (!kplane)
956 continue;
957
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300958 drm_plane = drm_plane_create(b, kplane);
Pekka Paalanenec272712014-06-05 11:22:25 +0300959 drmModeFreePlane(kplane);
960 if (!drm_plane)
961 continue;
962
Daniel Stone085d2b92015-05-21 00:00:57 +0100963 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
964 weston_compositor_stack_plane(b->compositor,
965 &drm_plane->base,
966 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +0300967 }
968
969 drmModeFreePlaneResources(kplane_res);
970}
971
972/**
973 * Clean up sprites (overlay planes)
974 *
975 * The counterpart to create_sprites.
976 *
977 * @param b DRM compositor backend
978 */
979static void
980destroy_sprites(struct drm_backend *b)
981{
982 struct drm_plane *plane, *next;
983
Daniel Stone085d2b92015-05-21 00:00:57 +0100984 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +0300985 drm_plane_destroy(plane);
986}
987
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -0300988/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200989static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +0300990drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200991{
992 long brightness, max_brightness, norm;
993
Pekka Paalanence724242017-09-04 12:21:24 +0300994 brightness = backlight_get_brightness(head->backlight);
995 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200996
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -0300997 /* convert it on a scale of 0 to 255 */
998 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200999
1000 return (uint32_t) norm;
1001}
1002
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001003/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001004static void
1005drm_set_backlight(struct weston_output *output_base, uint32_t value)
1006{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001007 struct drm_output *output = to_drm_output(output_base);
1008 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001009 long max_brightness, new_brightness;
1010
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001011 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001012 return;
1013
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001014 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1015 if (!head->backlight)
1016 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001017
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001018 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001019
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001020 /* get denormalized value */
1021 new_brightness = (value * max_brightness) / 255;
1022
1023 backlight_set_brightness(head->backlight, new_brightness);
1024 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001025}
1026
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001027static void
1028drm_output_init_backlight(struct drm_output *output)
1029{
1030 struct weston_head *base;
1031 struct drm_head *head;
1032
1033 output->base.set_backlight = NULL;
1034
1035 wl_list_for_each(base, &output->base.head_list, output_link) {
1036 head = to_drm_head(base);
1037
1038 if (head->backlight) {
1039 weston_log("Initialized backlight for head '%s', device %s\n",
1040 head->base.name, head->backlight->path);
1041
1042 if (!output->base.set_backlight) {
1043 output->base.set_backlight = drm_set_backlight;
1044 output->base.backlight_current =
1045 drm_get_backlight(head);
1046 }
1047 }
1048 }
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001049}
1050
Daniel Stonea08512f2016-11-08 17:46:10 +00001051/**
1052 * Power output on or off
1053 *
1054 * The DPMS/power level of an output is used to switch it on or off. This
1055 * is DRM's hook for doing so, which can called either as part of repaint,
1056 * or independently of the repaint loop.
1057 *
1058 * If we are called as part of repaint, we simply set the relevant bit in
1059 * state and return.
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001060 *
1061 * This function is never called on a virtual output.
Daniel Stonea08512f2016-11-08 17:46:10 +00001062 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001063static void
1064drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1065{
Armin Krezović545dba62016-08-05 15:54:18 +02001066 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00001067 struct drm_backend *b = to_drm_backend(output_base->compositor);
1068 struct drm_pending_state *pending_state = b->repaint_data;
1069 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01001070 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001071
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001072 assert(!output->virtual);
1073
Daniel Stonea08512f2016-11-08 17:46:10 +00001074 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001075 return;
1076
Daniel Stonea08512f2016-11-08 17:46:10 +00001077 /* If we're being called during the repaint loop, then this is
1078 * simple: discard any previously-generated state, and create a new
1079 * state where we disable everything. When we come to flush, this
1080 * will be applied.
1081 *
1082 * However, we need to be careful: we can be called whilst another
1083 * output is in its repaint cycle (pending_state exists), but our
1084 * output still has an incomplete state application outstanding.
1085 * In that case, we need to wait until that completes. */
1086 if (pending_state && !output->state_last) {
1087 /* The repaint loop already sets DPMS on; we don't need to
1088 * explicitly set it on here, as it will already happen
1089 * whilst applying the repaint state. */
1090 if (level == WESTON_DPMS_ON)
1091 return;
1092
1093 state = drm_pending_state_get_output(pending_state, output);
1094 if (state)
1095 drm_output_state_free(state);
1096 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01001097 return;
1098 }
1099
Daniel Stonea08512f2016-11-08 17:46:10 +00001100 /* As we throw everything away when disabling, just send us back through
1101 * a repaint cycle. */
1102 if (level == WESTON_DPMS_ON) {
1103 if (output->dpms_off_pending)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001104 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +00001105 weston_output_schedule_repaint(output_base);
1106 return;
1107 }
1108
1109 /* If we've already got a request in the pipeline, then we need to
1110 * park our DPMS request until that request has quiesced. */
1111 if (output->state_last) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001112 output->dpms_off_pending = true;
Daniel Stonea08512f2016-11-08 17:46:10 +00001113 return;
1114 }
1115
1116 pending_state = drm_pending_state_alloc(b);
1117 drm_output_get_disable_state(pending_state, output);
1118 ret = drm_pending_state_apply_sync(pending_state);
1119 if (ret != 0)
1120 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001121}
1122
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001123static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001124 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
1125 [DRM_MODE_CONNECTOR_VGA] = "VGA",
1126 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
1127 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
1128 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
1129 [DRM_MODE_CONNECTOR_Composite] = "Composite",
1130 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
1131 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
1132 [DRM_MODE_CONNECTOR_Component] = "Component",
1133 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
1134 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
1135 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
1136 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
1137 [DRM_MODE_CONNECTOR_TV] = "TV",
1138 [DRM_MODE_CONNECTOR_eDP] = "eDP",
1139 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
1140 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Stefan Agner30e283d2018-08-20 17:11:38 +02001141 [DRM_MODE_CONNECTOR_DPI] = "DPI",
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001142};
1143
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001144/** Create a name given a DRM connector
1145 *
1146 * \param con The DRM connector whose type and id form the name.
1147 * \return A newly allocate string, or NULL on error. Must be free()'d
1148 * after use.
1149 *
1150 * The name does not identify the DRM display device.
1151 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001152static char *
1153make_connector_name(const drmModeConnector *con)
1154{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001155 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001156 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001157 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001158
1159 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1160 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001161
1162 if (!type_name)
1163 type_name = "UNNAMED";
1164
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001165 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
1166 if (ret < 0)
1167 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001168
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001169 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001170}
1171
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001172static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001173drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001174{
Hardeningff39efa2013-09-18 23:56:35 +02001175 int w = output->base.current_mode->width;
1176 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001177 uint32_t format = output->gbm_format;
1178 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001179 unsigned int i;
Daniel Stone61abf352020-03-06 12:46:30 +00001180 const struct pixman_renderer_output_options options = {
1181 .use_shadow = b->use_pixman_shadow,
1182 };
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001183
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001184 switch (format) {
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001185 case DRM_FORMAT_XRGB8888:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001186 pixman_format = PIXMAN_x8r8g8b8;
1187 break;
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001188 case DRM_FORMAT_RGB565:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001189 pixman_format = PIXMAN_r5g6b5;
1190 break;
1191 default:
1192 weston_log("Unsupported pixman format 0x%x\n", format);
1193 return -1;
1194 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001195
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001196 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001197 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001198 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001199 if (!output->dumb[i])
1200 goto err;
1201
1202 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001203 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001204 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00001205 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001206 if (!output->image[i])
1207 goto err;
1208 }
1209
Daniel Stone61abf352020-03-06 12:46:30 +00001210 if (pixman_renderer_output_create(&output->base, &options) < 0)
Dongjin Kimba89f002024-09-30 17:49:36 +09001211 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05301212
Pekka Paalanendee412d2018-04-23 11:44:58 +02001213 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
1214 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001215
1216 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001217 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001218
1219 return 0;
1220
1221err:
1222 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1223 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01001224 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001225 if (output->image[i])
1226 pixman_image_unref(output->image[i]);
1227
1228 output->dumb[i] = NULL;
1229 output->image[i] = NULL;
1230 }
1231
1232 return -1;
1233}
1234
1235static void
1236drm_output_fini_pixman(struct drm_output *output)
1237{
Daniel Stonee2e80132018-01-16 15:37:33 +00001238 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001239 unsigned int i;
1240
Daniel Stonee2e80132018-01-16 15:37:33 +00001241 /* Destroying the Pixman surface will destroy all our buffers,
1242 * regardless of refcount. Ensure we destroy them here. */
1243 if (!b->shutting_down &&
1244 output->scanout_plane->state_cur->fb &&
1245 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
Alexandros Frantzis99751342020-05-18 15:22:49 +03001246 drm_plane_reset_state(output->scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +00001247 }
1248
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001249 pixman_renderer_output_destroy(&output->base);
1250 pixman_region32_fini(&output->previous_damage);
1251
1252 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001253 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001254 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001255 output->dumb[i] = NULL;
1256 output->image[i] = NULL;
1257 }
1258}
1259
Richard Hughes2b2092a2013-04-24 14:58:02 +01001260static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001261setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01001262 struct weston_output *output,
1263 const char *s)
1264{
1265 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05001266 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001267 struct udev_seat *seat;
1268
Giulio Camuffo954f1832014-10-11 18:27:30 +03001269 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05001270 if (!seat)
1271 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001272
Derek Foreman0720ea32015-07-15 13:00:35 -05001273 seat->base.output = output;
1274
Derek Foreman1281a362015-07-31 16:55:32 -05001275 pointer = weston_seat_get_pointer(&seat->base);
1276 if (pointer)
1277 weston_pointer_clamp(pointer,
1278 &pointer->x,
1279 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001280 }
1281}
1282
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001283static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03001284drm_output_attach_head(struct weston_output *output_base,
1285 struct weston_head *head_base)
1286{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001287 struct drm_backend *b = to_drm_backend(output_base->compositor);
1288
Pekka Paalanenc112f002017-08-28 16:27:20 +03001289 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
1290 return -1;
1291
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001292 if (!output_base->enabled)
1293 return 0;
1294
1295 /* XXX: ensure the configuration will work.
1296 * This is actually impossible without major infrastructure
1297 * work. */
1298
1299 /* Need to go through modeset to add connectors. */
1300 /* XXX: Ideally we'd do this per-output, not globally. */
1301 /* XXX: Doing it globally, what guarantees another output's update
1302 * will not clear the flag before this output is updated?
1303 */
1304 b->state_invalid = true;
1305
1306 weston_output_schedule_repaint(output_base);
1307
Pekka Paalanenc112f002017-08-28 16:27:20 +03001308 return 0;
1309}
1310
Pekka Paalanen7f853792017-11-29 14:33:33 +02001311static void
1312drm_output_detach_head(struct weston_output *output_base,
1313 struct weston_head *head_base)
1314{
1315 struct drm_backend *b = to_drm_backend(output_base->compositor);
1316
1317 if (!output_base->enabled)
1318 return;
1319
1320 /* Need to go through modeset to drop connectors that should no longer
1321 * be driven. */
1322 /* XXX: Ideally we'd do this per-output, not globally. */
1323 b->state_invalid = true;
1324
1325 weston_output_schedule_repaint(output_base);
1326}
1327
Stefan Agner3654c672019-07-09 00:50:30 +02001328int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001329parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001330{
Pekka Paalanen62a94362018-09-26 14:33:36 +03001331 const struct pixel_format_info *pinfo;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001332
Pekka Paalanen62a94362018-09-26 14:33:36 +03001333 if (s == NULL) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001334 *gbm_format = default_value;
Pekka Paalanen62a94362018-09-26 14:33:36 +03001335
1336 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001337 }
1338
Pekka Paalanen62a94362018-09-26 14:33:36 +03001339 pinfo = pixel_format_get_info_by_drm_name(s);
1340 if (!pinfo) {
1341 weston_log("fatal: unrecognized pixel format: %s\n", s);
1342
1343 return -1;
1344 }
1345
1346 /* GBM formats and DRM formats are identical. */
1347 *gbm_format = pinfo->format;
1348
1349 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001350}
1351
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001352static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001353drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001354{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001355 int drm_fd = backend->drm.fd;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001356 drmModeConnector *conn = head->connector.conn;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001357 drmModeEncoder *encoder;
1358 drmModeCrtc *crtc;
1359
1360 /* Get the current mode on the crtc that's currently driving
1361 * this connector. */
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001362 encoder = drmModeGetEncoder(drm_fd, conn->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001363 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001364 head->inherited_crtc_id = encoder->crtc_id;
1365
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001366 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
1367 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001368
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001369 if (crtc == NULL)
1370 return -1;
1371 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02001372 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001373 drmModeFreeCrtc(crtc);
1374 }
1375
1376 return 0;
1377}
1378
Armin Krezović08368132016-09-30 14:11:05 +02001379static void
1380drm_output_set_gbm_format(struct weston_output *base,
1381 const char *gbm_format)
1382{
1383 struct drm_output *output = to_drm_output(base);
1384 struct drm_backend *b = to_drm_backend(base->compositor);
1385
1386 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
1387 output->gbm_format = b->gbm_format;
1388}
1389
1390static void
1391drm_output_set_seat(struct weston_output *base,
1392 const char *seat)
1393{
1394 struct drm_output *output = to_drm_output(base);
1395 struct drm_backend *b = to_drm_backend(base->compositor);
1396
1397 setup_output_seat_constraint(b, &output->base,
1398 seat ? seat : "");
1399}
1400
1401static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001402drm_output_init_gamma_size(struct drm_output *output)
1403{
1404 struct drm_backend *backend = to_drm_backend(output->base.compositor);
1405 drmModeCrtc *crtc;
1406
1407 assert(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001408 assert(output->crtc);
1409 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc->crtc_id);
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001410 if (!crtc)
1411 return -1;
1412
1413 output->base.gamma_size = crtc->gamma_size;
1414
1415 drmModeFreeCrtc(crtc);
1416
1417 return 0;
1418}
1419
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001420static uint32_t
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001421drm_connector_get_possible_crtcs_mask(struct drm_connector *connector)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001422{
1423 uint32_t possible_crtcs = 0;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001424 drmModeConnector *conn = connector->conn;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001425 drmModeEncoder *encoder;
1426 int i;
1427
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001428 for (i = 0; i < conn->count_encoders; i++) {
1429 encoder = drmModeGetEncoder(connector->backend->drm.fd,
1430 conn->encoders[i]);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001431 if (!encoder)
1432 continue;
1433
1434 possible_crtcs |= encoder->possible_crtcs;
1435 drmModeFreeEncoder(encoder);
1436 }
1437
1438 return possible_crtcs;
1439}
1440
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001441/** Pick a CRTC that might be able to drive all attached connectors
1442 *
1443 * @param output The output whose attached heads to include.
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001444 * @return CRTC object to pick, or NULL on failure or not found.
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001445 */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001446static struct drm_crtc *
1447drm_output_pick_crtc(struct drm_output *output)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001448{
1449 struct drm_backend *backend;
1450 struct weston_head *base;
1451 struct drm_head *head;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001452 struct drm_crtc *crtc;
1453 struct drm_crtc *best_crtc = NULL;
1454 struct drm_crtc *fallback_crtc = NULL;
1455 struct drm_crtc *existing_crtc[32];
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001456 uint32_t possible_crtcs = 0xffffffff;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001457 unsigned n = 0;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001458 uint32_t crtc_id;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001459 unsigned int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001460 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001461
1462 backend = to_drm_backend(output->base.compositor);
1463
1464 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
1465 * because it is more often set wrong than not in the kernel. */
1466
1467 /* Accumulate a mask of possible crtcs and find existing routings. */
1468 wl_list_for_each(base, &output->base.head_list, output_link) {
1469 head = to_drm_head(base);
1470
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001471 possible_crtcs &=
1472 drm_connector_get_possible_crtcs_mask(&head->connector);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001473
1474 crtc_id = head->inherited_crtc_id;
1475 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001476 existing_crtc[n++] = drm_crtc_find(backend, crtc_id);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001477 }
1478
1479 /* Find a crtc that could drive each connector individually at least,
1480 * and prefer existing routings. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001481 wl_list_for_each(crtc, &backend->crtc_list, link) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001482
1483 /* Could the crtc not drive each connector? */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001484 if (!(possible_crtcs & (1 << crtc->pipe)))
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001485 continue;
1486
1487 /* Is the crtc already in use? */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001488 if (crtc->output)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001489 continue;
1490
1491 /* Try to preserve the existing CRTC -> connector routing;
1492 * it makes initialisation faster, and also since we have a
1493 * very dumb picking algorithm, may preserve a better
1494 * choice. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001495 for (i = 0; i < n; i++) {
1496 if (existing_crtc[i] == crtc)
1497 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001498 }
1499
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001500 /* Check if any other head had existing routing to this CRTC.
1501 * If they did, this is not the best CRTC as it might be needed
1502 * for another output we haven't enabled yet. */
1503 match = false;
1504 wl_list_for_each(base, &backend->compositor->head_list,
1505 compositor_link) {
1506 head = to_drm_head(base);
1507
1508 if (head->base.output == &output->base)
1509 continue;
1510
1511 if (weston_head_is_enabled(&head->base))
1512 continue;
1513
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001514 if (head->inherited_crtc_id == crtc->crtc_id) {
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001515 match = true;
1516 break;
1517 }
1518 }
1519 if (!match)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001520 best_crtc = crtc;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001521
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001522 fallback_crtc = crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001523 }
1524
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001525 if (best_crtc)
1526 return best_crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001527
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001528 if (fallback_crtc)
1529 return fallback_crtc;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001530
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001531 /* Likely possible_crtcs was empty due to asking for clones,
1532 * but since the DRM documentation says the kernel lies, let's
1533 * pick one crtc anyway. Trial and error is the only way to
1534 * be sure if something doesn't work. */
1535
1536 /* First pick any existing assignment. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001537 for (i = 0; i < n; i++) {
1538 crtc = existing_crtc[i];
1539 if (!crtc->output)
1540 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001541 }
1542
1543 /* Otherwise pick any available crtc. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001544 wl_list_for_each(crtc, &backend->crtc_list, link) {
1545 if (!crtc->output)
1546 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001547 }
1548
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001549 return NULL;
1550}
1551
1552/** Create an "empty" drm_crtc. It will only set its ID, pipe and props. After
1553 * all, it adds the object to the DRM-backend CRTC list.
1554 */
1555static struct drm_crtc *
1556drm_crtc_create(struct drm_backend *b, uint32_t crtc_id, uint32_t pipe)
1557{
1558 struct drm_crtc *crtc;
1559 drmModeObjectPropertiesPtr props;
1560
1561 props = drmModeObjectGetProperties(b->drm.fd, crtc_id,
1562 DRM_MODE_OBJECT_CRTC);
1563 if (!props) {
1564 weston_log("failed to get CRTC properties\n");
1565 return NULL;
1566 }
1567
1568 crtc = zalloc(sizeof(*crtc));
1569 if (!crtc)
1570 goto ret;
1571
1572 drm_property_info_populate(b, crtc_props, crtc->props_crtc,
1573 WDRM_CRTC__COUNT, props);
1574 crtc->backend = b;
1575 crtc->crtc_id = crtc_id;
1576 crtc->pipe = pipe;
1577 crtc->output = NULL;
1578
1579 /* Add it to the last position of the DRM-backend CRTC list */
1580 wl_list_insert(b->crtc_list.prev, &crtc->link);
1581
1582ret:
1583 drmModeFreeObjectProperties(props);
1584 return crtc;
1585}
1586
1587/** Destroy a drm_crtc object that was created with drm_crtc_create(). It will
1588 * also remove it from the DRM-backend CRTC list.
1589 */
1590static void
1591drm_crtc_destroy(struct drm_crtc *crtc)
1592{
1593 /* TODO: address the issue below to be able to remove the comment
1594 * from the assert.
1595 *
1596 * https://gitlab.freedesktop.org/wayland/weston/-/issues/421
1597 */
1598
1599 //assert(!crtc->output);
1600
1601 wl_list_remove(&crtc->link);
1602 drm_property_info_free(crtc->props_crtc, WDRM_CRTC__COUNT);
1603 free(crtc);
1604}
1605
1606/** Find all CRTCs of the fd and create drm_crtc objects for them.
1607 *
1608 * The CRTCs are saved in a list of the drm_backend and will keep there until
1609 * the fd gets closed.
1610 *
1611 * @param b The DRM-backend structure.
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03001612 * @param resources The DRM resources, it is taken with drmModeGetResources
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001613 * @return 0 on success (at least one CRTC in the list), -1 on failure.
1614 */
1615static int
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03001616drm_backend_create_crtc_list(struct drm_backend *b, drmModeRes *resources)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001617{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001618 struct drm_crtc *crtc, *crtc_tmp;
1619 int i;
1620
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001621 /* Iterate through all CRTCs */
1622 for (i = 0; i < resources->count_crtcs; i++) {
1623
1624 /* Let's create an object for the CRTC and add it to the list */
1625 crtc = drm_crtc_create(b, resources->crtcs[i], i);
1626 if (!crtc)
1627 goto err;
1628 }
1629
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001630 return 0;
1631
1632err:
1633 wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
1634 drm_crtc_destroy(crtc);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001635 return -1;
1636}
1637
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001638
1639/** Populates scanout and cursor planes for the output. Also sets the topology
1640 * of the planes by adding them to the plane stacking list.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001641 */
1642static int
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001643drm_output_init_planes(struct drm_output *output)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001644{
1645 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001646
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001647 output->scanout_plane =
1648 drm_output_find_special_plane(b, output,
1649 WDRM_PLANE_TYPE_PRIMARY);
1650 if (!output->scanout_plane) {
1651 weston_log("Failed to find primary plane for output %s\n",
1652 output->base.name);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001653 return -1;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001654 }
1655
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001656 weston_compositor_stack_plane(b->compositor,
1657 &output->scanout_plane->base,
1658 &b->compositor->primary_plane);
1659
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001660 /* Failing to find a cursor plane is not fatal, as we'll fall back
1661 * to software cursor. */
1662 output->cursor_plane =
1663 drm_output_find_special_plane(b, output,
1664 WDRM_PLANE_TYPE_CURSOR);
1665
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001666 if (output->cursor_plane)
1667 weston_compositor_stack_plane(b->compositor,
1668 &output->cursor_plane->base,
1669 NULL);
1670 else
1671 b->cursors_are_broken = true;
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001672
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001673 return 0;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001674}
1675
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001676/** The opposite of drm_output_init_planes(). First of all it removes the planes
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001677 * from the plane stacking list. After all it sets the planes of the output as NULL.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001678 */
1679static void
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001680drm_output_deinit_planes(struct drm_output *output)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001681{
1682 struct drm_backend *b = to_drm_backend(output->base.compositor);
1683
Alexandros Frantzis53a71cb2020-05-18 15:26:01 +03001684 /* If the compositor is already shutting down, the planes have already
1685 * been destroyed. */
1686 if (!b->shutting_down) {
Pekka Paalanen3d6721e2020-09-16 15:04:04 +03001687 wl_list_remove(&output->scanout_plane->base.link);
1688 wl_list_init(&output->scanout_plane->base.link);
1689
1690 if (output->cursor_plane) {
1691 wl_list_remove(&output->cursor_plane->base.link);
1692 wl_list_init(&output->cursor_plane->base.link);
1693 /* Turn off hardware cursor */
1694 drmModeSetCursor(b->drm.fd, output->crtc->crtc_id, 0, 0, 0);
1695 }
1696
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001697 /* With universal planes, the planes are allocated at startup,
1698 * freed at shutdown, and live on the plane list in between.
1699 * We want the planes to continue to exist and be freed up
1700 * for other outputs.
1701 */
1702 if (output->cursor_plane)
1703 drm_plane_reset_state(output->cursor_plane);
1704 if (output->scanout_plane)
1705 drm_plane_reset_state(output->scanout_plane);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001706 }
1707
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001708 output->cursor_plane = NULL;
1709 output->scanout_plane = NULL;
1710}
1711
Leandro Ribeiro54293022021-10-12 14:48:36 -03001712static struct weston_drm_format_array *
1713get_scanout_formats(struct drm_backend *b)
1714{
1715 struct weston_compositor *ec = b->compositor;
1716 const struct weston_drm_format_array *renderer_formats;
1717 struct weston_drm_format_array *scanout_formats, union_planes_formats;
1718 struct drm_plane *plane;
1719 int ret;
1720
1721 /* If we got here it means that dma-buf feedback is supported and that
1722 * the renderer has formats/modifiers to expose. */
1723 assert(ec->renderer->get_supported_formats != NULL);
1724 renderer_formats = ec->renderer->get_supported_formats(ec);
1725
1726 scanout_formats = zalloc(sizeof(*scanout_formats));
1727 if (!scanout_formats) {
1728 weston_log("%s: out of memory\n", __func__);
1729 return NULL;
1730 }
1731
1732 weston_drm_format_array_init(&union_planes_formats);
1733 weston_drm_format_array_init(scanout_formats);
1734
1735 /* Compute the union of the format/modifiers of the KMS planes */
1736 wl_list_for_each(plane, &b->plane_list, link) {
1737 /* The scanout formats are used by the dma-buf feedback. But for
1738 * now cursor planes do not support dma-buf buffers, only wl_shm
1739 * buffers. So we skip cursor planes here. */
1740 if (plane->type == WDRM_PLANE_TYPE_CURSOR)
1741 continue;
1742
1743 ret = weston_drm_format_array_join(&union_planes_formats,
1744 &plane->formats);
1745 if (ret < 0)
1746 goto err;
1747 }
1748
1749 /* Compute the intersection between the union of format/modifiers of KMS
1750 * planes and the formats supported by the renderer */
1751 ret = weston_drm_format_array_replace(scanout_formats,
1752 renderer_formats);
1753 if (ret < 0)
1754 goto err;
1755
1756 ret = weston_drm_format_array_intersect(scanout_formats,
1757 &union_planes_formats);
1758 if (ret < 0)
1759 goto err;
1760
1761 weston_drm_format_array_fini(&union_planes_formats);
1762
1763 return scanout_formats;
1764
1765err:
1766 weston_drm_format_array_fini(&union_planes_formats);
1767 weston_drm_format_array_fini(scanout_formats);
Daniel Stonef5086032021-12-06 16:52:19 +00001768 free(scanout_formats);
Leandro Ribeiro54293022021-10-12 14:48:36 -03001769 return NULL;
1770}
1771
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001772/** Pick a CRTC and reserve it for the output.
1773 *
1774 * On failure, the output remains without a CRTC.
1775 *
1776 * @param output The output with no CRTC associated.
1777 * @return 0 on success, -1 on failure.
1778 */
1779static int
1780drm_output_attach_crtc(struct drm_output *output)
1781{
1782 output->crtc = drm_output_pick_crtc(output);
1783 if (!output->crtc) {
1784 weston_log("Output '%s': No available CRTCs.\n",
1785 output->base.name);
1786 return -1;
1787 }
1788
1789 /* Reserve the CRTC for the output */
1790 output->crtc->output = output;
1791
1792 return 0;
1793}
1794
1795/** Release reservation of the CRTC.
1796 *
1797 * Make the CRTC free to be reserved and used by another output.
1798 *
1799 * @param output The output that will release its CRTC.
1800 */
1801static void
1802drm_output_detach_crtc(struct drm_output *output)
1803{
1804 struct drm_backend *b = output->backend;
1805 struct drm_crtc *crtc = output->crtc;
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001806
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001807 crtc->output = NULL;
1808 output->crtc = NULL;
1809
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001810 /* Force resetting unused CRTCs */
1811 b->state_invalid = true;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001812}
1813
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001814static int
Armin Krezović08368132016-09-30 14:11:05 +02001815drm_output_enable(struct weston_output *base)
1816{
1817 struct drm_output *output = to_drm_output(base);
1818 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001819 int ret;
1820
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001821 assert(!output->virtual);
1822
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001823 ret = drm_output_attach_crtc(output);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001824 if (ret < 0)
1825 return -1;
1826
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001827 ret = drm_output_init_planes(output);
1828 if (ret < 0)
1829 goto err_crtc;
1830
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001831 if (drm_output_init_gamma_size(output) < 0)
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001832 goto err_planes;
Armin Krezović08368132016-09-30 14:11:05 +02001833
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001834 if (b->pageflip_timeout)
1835 drm_output_pageflip_timer_create(output);
1836
Giulio Camuffo954f1832014-10-11 18:27:30 +03001837 if (b->use_pixman) {
1838 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001839 weston_log("Failed to init output pixman state\n");
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001840 goto err_planes;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001841 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03001842 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001843 weston_log("Failed to init output gl state\n");
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001844 goto err_planes;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001845 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001846
leng.fang32af9fc2024-06-13 11:22:15 +08001847 drm_enable_aml_output_config(output, base, b);
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001848 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001849
Jonas Ådahle5a12252013-04-05 23:07:11 +02001850 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001851 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001852 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001853 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001854 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01001855 output->base.set_gamma = drm_output_set_gamma;
1856
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001857 weston_log("Output %s (crtc %d) video modes:\n",
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001858 output->base.name, output->crtc->crtc_id);
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001859 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001860
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001861 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001862
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001863err_planes:
1864 drm_output_deinit_planes(output);
1865err_crtc:
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001866 drm_output_detach_crtc(output);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001867 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001868}
1869
Jesse Barnes58ef3792012-02-23 09:45:49 -05001870static void
Armin Krezović08368132016-09-30 14:11:05 +02001871drm_output_deinit(struct weston_output *base)
1872{
1873 struct drm_output *output = to_drm_output(base);
1874 struct drm_backend *b = to_drm_backend(base->compositor);
1875
Daniel Stone3e661f72016-11-04 17:24:06 +00001876 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02001877 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00001878 else
1879 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02001880
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001881 drm_output_deinit_planes(output);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001882 drm_output_detach_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02001883}
1884
1885static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03001886drm_head_destroy(struct drm_head *head);
1887
1888static void
Armin Krezović08368132016-09-30 14:11:05 +02001889drm_output_destroy(struct weston_output *base)
1890{
1891 struct drm_output *output = to_drm_output(base);
1892 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02001893
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001894 assert(!output->virtual);
1895
Daniel Stone31838bf2019-06-17 11:23:25 +01001896 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001897 output->destroy_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001898 weston_log("destroy output while page flip pending\n");
1899 return;
1900 }
1901
Alexandros Frantzis10937fe2021-06-14 13:09:44 +03001902 drm_output_set_cursor_view(output, NULL);
1903
Armin Krezović08368132016-09-30 14:11:05 +02001904 if (output->base.enabled)
1905 drm_output_deinit(&output->base);
1906
Pekka Paalanen383b3af2017-09-11 14:40:48 +03001907 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02001908
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001909 if (output->pageflip_timer)
1910 wl_event_source_remove(output->pageflip_timer);
1911
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03001912 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02001913
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001914 assert(!output->state_last);
1915 drm_output_state_free(output->state_cur);
1916
Armin Krezović08368132016-09-30 14:11:05 +02001917 free(output);
1918}
1919
1920static int
1921drm_output_disable(struct weston_output *base)
1922{
1923 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02001924
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001925 assert(!output->virtual);
leng.fang32af9fc2024-06-13 11:22:15 +08001926 drm_output_disable_aml(output, base);
Daniel Stonea08512f2016-11-08 17:46:10 +00001927
Armin Krezović08368132016-09-30 14:11:05 +02001928 if (output->base.enabled)
1929 drm_output_deinit(&output->base);
1930
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001931 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02001932
Armin Krezović08368132016-09-30 14:11:05 +02001933 return 0;
1934}
1935
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301936/*
1937 * This function converts the protection status from drm values to
1938 * weston_hdcp_protection status. The drm values as read from the connector
1939 * properties "Content Protection" and "HDCP Content Type" need to be converted
1940 * to appropriate weston values, that can be sent to a client application.
1941 */
1942static int
1943get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
1944 enum wdrm_hdcp_content_type type,
1945 enum weston_hdcp_protection *weston_protection)
1946
1947{
1948 if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
1949 return -1;
1950 if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
1951 protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
1952 *weston_protection = WESTON_HDCP_DISABLE;
1953 return 0;
1954 }
1955 if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
1956 return -1;
1957 if (type == WDRM_HDCP_CONTENT_TYPE0) {
1958 *weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
1959 return 0;
1960 }
1961 if (type == WDRM_HDCP_CONTENT_TYPE1) {
1962 *weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
1963 return 0;
1964 }
1965 return -1;
1966}
1967
1968/**
1969 * Get current content-protection status for a given head.
1970 *
1971 * @param head drm_head, whose protection is to be retrieved
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301972 * @return protection status in case of success, -1 otherwise
1973 */
1974static enum weston_hdcp_protection
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03001975drm_head_get_current_protection(struct drm_head *head)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301976{
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03001977 drmModeObjectProperties *props = head->connector.props_drm;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301978 struct drm_property_info *info;
1979 enum wdrm_content_protection_state protection;
1980 enum wdrm_hdcp_content_type type;
1981 enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
1982
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001983 info = &head->connector.props[WDRM_CONNECTOR_CONTENT_PROTECTION];
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301984 protection = drm_property_get_value(info, props,
1985 WDRM_CONTENT_PROTECTION__COUNT);
1986
1987 if (protection == WDRM_CONTENT_PROTECTION__COUNT)
1988 return WESTON_HDCP_DISABLE;
1989
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001990 info = &head->connector.props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301991 type = drm_property_get_value(info, props,
1992 WDRM_HDCP_CONTENT_TYPE__COUNT);
1993
1994 /*
1995 * In case of platforms supporting HDCP1.4, only property
1996 * 'Content Protection' is exposed and not the 'HDCP Content Type'
1997 * for such cases HDCP Type 0 should be considered as the content-type.
1998 */
1999
2000 if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
2001 type = WDRM_HDCP_CONTENT_TYPE0;
2002
2003 if (get_weston_protection_from_drm(protection, type,
2004 &weston_hdcp) == -1) {
2005 weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
2006 protection, type, head->base.name,
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002007 head->connector.connector_id);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302008 return WESTON_HDCP_DISABLE;
2009 }
2010
2011 return weston_hdcp;
2012}
2013
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002014static int
2015drm_connector_update_properties(struct drm_connector *connector)
2016{
2017 drmModeObjectProperties *props;
2018
2019 props = drmModeObjectGetProperties(connector->backend->drm.fd,
2020 connector->connector_id,
2021 DRM_MODE_OBJECT_CONNECTOR);
2022 if (!props) {
2023 weston_log("Error: failed to get connector properties\n");
2024 return -1;
2025 }
2026
2027 if (connector->props_drm)
2028 drmModeFreeObjectProperties(connector->props_drm);
2029 connector->props_drm = props;
2030
2031 return 0;
2032}
2033
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002034/** Replace connector data and monitor information
2035 *
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002036 * @param connector The drm_connector object to be updated.
2037 * @param conn The connector data to be owned by the drm_connector, must match
2038 * the current drm_connector ID.
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002039 * @return 0 on success, -1 on failure.
2040 *
2041 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002042 */
2043static int
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002044drm_connector_assign_connector_info(struct drm_connector *connector,
2045 drmModeConnector *conn)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002046{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002047 assert(connector->conn != conn);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002048 assert(connector->connector_id == conn->connector_id);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002049
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002050 if (drm_connector_update_properties(connector) < 0)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002051 return -1;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002052
leng.fang32af9fc2024-06-13 11:22:15 +08002053 drm_update_helper_connector(connector, conn);
2054
Leandro Ribeiro70863962020-09-09 13:12:35 -03002055 if (connector->conn)
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002056 drmModeFreeConnector(connector->conn);
2057 connector->conn = conn;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002058
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002059 drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
2060 drm_property_info_populate(connector->backend, connector_props,
2061 connector->props,
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002062 WDRM_CONNECTOR__COUNT, connector->props_drm);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002063 return 0;
2064}
2065
Leandro Ribeiro70863962020-09-09 13:12:35 -03002066static void
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002067drm_connector_init(struct drm_backend *b, struct drm_connector *connector,
2068 uint32_t connector_id)
2069{
2070 connector->backend = b;
2071 connector->connector_id = connector_id;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002072 connector->conn = NULL;
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002073 connector->props_drm = NULL;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002074}
2075
2076static void
2077drm_connector_fini(struct drm_connector *connector)
2078{
2079 drmModeFreeConnector(connector->conn);
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002080 drmModeFreeObjectProperties(connector->props_drm);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002081 drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
2082}
2083
Pekka Paalanen456dc732017-11-09 15:10:11 +02002084static void
2085drm_head_log_info(struct drm_head *head, const char *msg)
2086{
2087 if (head->base.connected) {
2088 weston_log("DRM: head '%s' %s, connector %d is connected, "
2089 "EDID make '%s', model '%s', serial '%s'\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002090 head->base.name, msg, head->connector.connector_id,
Pekka Paalanen456dc732017-11-09 15:10:11 +02002091 head->base.make, head->base.model,
2092 head->base.serial_number ?: "");
2093 } else {
2094 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002095 head->base.name, msg, head->connector.connector_id);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002096 }
2097}
2098
Pekka Paalanend2e62422017-09-08 15:48:07 +03002099/** Update connector and monitor information
2100 *
2101 * @param head The head to update.
Leandro Ribeiro70863962020-09-09 13:12:35 -03002102 * @param conn The DRM connector object.
2103 * @returns 0 on success, -1 on failure.
Pekka Paalanend2e62422017-09-08 15:48:07 +03002104 *
Leandro Ribeiro70863962020-09-09 13:12:35 -03002105 * Updates monitor information and connection status. This may schedule a
2106 * heads changed call to the user.
Leandro Ribeiro4a5b67a2020-09-15 15:30:35 -03002107 *
2108 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanend2e62422017-09-08 15:48:07 +03002109 */
Leandro Ribeiro70863962020-09-09 13:12:35 -03002110static int
2111drm_head_update_info(struct drm_head *head, drmModeConnector *conn)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002112{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002113 int ret;
Pekka Paalanend2e62422017-09-08 15:48:07 +03002114
Leandro Ribeiro70863962020-09-09 13:12:35 -03002115 ret = drm_connector_assign_connector_info(&head->connector, conn);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002116
Leandro Ribeiro67941642020-09-15 00:11:02 -03002117 update_head_from_connector(head);
2118 weston_head_set_content_protection_status(&head->base,
2119 drm_head_get_current_protection(head));
2120
leng.fang91856072024-06-07 14:12:54 +08002121#ifdef ENABLE_MODE_POLICY
leng.fang69a93e32024-08-08 16:31:01 +08002122 init_mode_policy_without_mode(&head->base,
2123 head->backend->drm.fd, head->connector.conn);
2124
leng.fang3e8a4b52024-07-24 14:51:30 +08002125 if (head->base.device_changed) {
2126 mode_policy_set_head(&head->base);
leng.fang69a93e32024-08-08 16:31:01 +08002127 mode_policy_set_state(&head->base, head->base.connected ?
leng.fang13fd3982024-07-03 19:09:58 +08002128 AML_WESTON_HOTPLUG_PLUG : AML_WESTON_HOTPLUG_UNPLUG, false);
leng.fang3e8a4b52024-07-24 14:51:30 +08002129 }
leng.fang91856072024-06-07 14:12:54 +08002130#endif
2131
Pekka Paalanen456dc732017-11-09 15:10:11 +02002132 if (head->base.device_changed)
2133 drm_head_log_info(head, "updated");
Leandro Ribeiro70863962020-09-09 13:12:35 -03002134
2135 return ret;
Pekka Paalanend2e62422017-09-08 15:48:07 +03002136}
2137
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002138/** Update writeback connector
2139 *
2140 * @param writeback The writeback to update.
2141 * @param conn DRM connector object.
2142 * @returns 0 on success, -1 on failure.
2143 *
2144 * Takes ownership of @c connector on success, not on failure.
2145 */
2146static int
2147drm_writeback_update_info(struct drm_writeback *writeback, drmModeConnector *conn)
2148{
2149 int ret;
2150
2151 ret = drm_connector_assign_connector_info(&writeback->connector, conn);
2152
2153 return ret;
2154}
2155
Daniel Stone087ddf02017-02-14 17:51:30 +00002156/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03002157 * Create a Weston head for a connector
2158 *
2159 * Given a DRM connector, create a matching drm_head structure and add it
2160 * to Weston's head list.
2161 *
Marius Vlada2dace22019-06-12 16:05:44 +03002162 * @param backend Weston backend structure
Leandro Ribeiro70863962020-09-09 13:12:35 -03002163 * @param conn DRM connector object
Pekka Paalanenc112f002017-08-28 16:27:20 +03002164 * @param drm_device udev device pointer
Leandro Ribeiro70863962020-09-09 13:12:35 -03002165 * @returns 0 on success, -1 on failure
Leandro Ribeiro4a5b67a2020-09-15 15:30:35 -03002166 *
2167 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanenc112f002017-08-28 16:27:20 +03002168 */
Leandro Ribeiro70863962020-09-09 13:12:35 -03002169static int
2170drm_head_create(struct drm_backend *backend, drmModeConnector *conn,
Pekka Paalanenc112f002017-08-28 16:27:20 +03002171 struct udev_device *drm_device)
2172{
2173 struct drm_head *head;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002174 char *name;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002175 int ret;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002176
2177 head = zalloc(sizeof *head);
2178 if (!head)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002179 return -1;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002180
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002181 head->backend = backend;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002182
Leandro Ribeiro70863962020-09-09 13:12:35 -03002183 drm_connector_init(backend, &head->connector, conn->connector_id);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002184
2185 name = make_connector_name(conn);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002186 if (!name)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002187 goto err;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002188
2189 weston_head_init(&head->base, name);
2190 free(name);
2191
Leandro Ribeiro67941642020-09-15 00:11:02 -03002192 ret = drm_head_update_info(head, conn);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002193 if (ret < 0)
Leandro Ribeiro67941642020-09-15 00:11:02 -03002194 goto err_update;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002195
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002196 head->backlight = backlight_init(drm_device, conn->connector_type);
Pekka Paalanence724242017-09-04 12:21:24 +03002197
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002198 if (conn->connector_type == DRM_MODE_CONNECTOR_LVDS ||
2199 conn->connector_type == DRM_MODE_CONNECTOR_eDP)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002200 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002201
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02002202 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002203 weston_log("Failed to retrieve current mode from connector %d.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002204 head->connector.connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02002205 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002206 }
2207
Pekka Paalanenc112f002017-08-28 16:27:20 +03002208 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002209 drm_head_log_info(head, "found");
leng.fang32af9fc2024-06-13 11:22:15 +08002210 drm_append_helper_connector(head);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002211
Leandro Ribeiro70863962020-09-09 13:12:35 -03002212 return 0;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002213
Leandro Ribeiro67941642020-09-15 00:11:02 -03002214err_update:
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002215 weston_head_release(&head->base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002216err:
Leandro Ribeiro70863962020-09-09 13:12:35 -03002217 drm_connector_fini(&head->connector);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002218 free(head);
Leandro Ribeiro70863962020-09-09 13:12:35 -03002219 return -1;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002220}
2221
2222static void
2223drm_head_destroy(struct drm_head *head)
2224{
leng.fang32af9fc2024-06-13 11:22:15 +08002225 drm_delete_helper_connector(head);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002226 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03002227
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002228 drm_connector_fini(&head->connector);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002229
Pekka Paalanence724242017-09-04 12:21:24 +03002230 if (head->backlight)
2231 backlight_destroy(head->backlight);
2232
Pekka Paalanenc112f002017-08-28 16:27:20 +03002233 free(head);
2234}
2235
2236/**
Armin Krezović08368132016-09-30 14:11:05 +02002237 * Create a Weston output structure
2238 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002239 * Create an "empty" drm_output. This is the implementation of
2240 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02002241 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002242 * Creating an output is usually followed by drm_output_attach_head()
2243 * and drm_output_enable() to make use of it.
2244 *
2245 * @param compositor The compositor instance.
2246 * @param name Name for the new output.
2247 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02002248 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03002249static struct weston_output *
2250drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02002251{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002252 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02002253 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02002254
Armin Krezović08368132016-09-30 14:11:05 +02002255 output = zalloc(sizeof *output);
2256 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002257 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02002258
Daniel Stone64dbbee2018-07-20 19:00:06 +01002259 output->backend = b;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002260 output->crtc = NULL;
2261
Stefan Agnerccf24072019-07-09 22:02:00 +02002262#ifdef BUILD_DRM_GBM
Tomohito Esaki718a40b2018-01-31 17:50:15 +09002263 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Stefan Agnerccf24072019-07-09 22:02:00 +02002264#endif
Daniel Stone64dbbee2018-07-20 19:00:06 +01002265
Pekka Paalanend2e62422017-09-08 15:48:07 +03002266 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002267
Armin Krezović08368132016-09-30 14:11:05 +02002268 output->base.enable = drm_output_enable;
2269 output->base.destroy = drm_output_destroy;
2270 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002271 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02002272 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02002273
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002274 output->destroy_pending = false;
2275 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02002276
Pekka Paalanen01f60212017-03-24 15:39:24 +02002277 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03002278
leng.fang32af9fc2024-06-13 11:22:15 +08002279 drm_init_aml_output_config(compositor, output);
Armin Krezović08368132016-09-30 14:11:05 +02002280 weston_compositor_add_pending_output(&output->base, b->compositor);
2281
Pekka Paalanend2e62422017-09-08 15:48:07 +03002282 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02002283}
2284
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002285/**
2286 * Create a Weston writeback for a writeback connector
Leandro Ribeiro72430222020-09-14 17:41:41 -03002287 *
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002288 * Given a DRM connector of type writeback, create a matching drm_writeback
2289 * structure and add it to Weston's writeback list.
2290 *
2291 * @param b Weston backend structure
2292 * @param conn DRM connector object of type writeback
2293 * @returns 0 on success, -1 on failure
2294 *
2295 * Takes ownership of @c connector on success, not on failure.
2296 */
2297static int
2298drm_writeback_create(struct drm_backend *b, drmModeConnector *conn)
2299{
2300 struct drm_writeback *writeback;
2301 int ret;
2302
2303 writeback = zalloc(sizeof *writeback);
2304 assert(writeback);
2305
2306 writeback->backend = b;
2307
2308 drm_connector_init(b, &writeback->connector, conn->connector_id);
2309
2310 ret = drm_writeback_update_info(writeback, conn);
2311 if (ret < 0)
2312 goto err;
2313
2314 wl_list_insert(&b->writeback_connector_list, &writeback->link);
2315 return 0;
2316
2317err:
2318 drm_connector_fini(&writeback->connector);
2319 free(writeback);
2320 return -1;
2321}
2322
2323static void
2324drm_writeback_destroy(struct drm_writeback *writeback)
2325{
2326 drm_connector_fini(&writeback->connector);
2327 wl_list_remove(&writeback->link);
2328
2329 free(writeback);
2330}
2331
2332/** Given the DRM connector object of a connector, create drm_head or
2333 * drm_writeback object (depending on the type of connector) for it.
2334 *
2335 * The object is then added to the DRM-backend list of heads or writebacks.
Leandro Ribeiro72430222020-09-14 17:41:41 -03002336 *
2337 * @param b The DRM-backend structure
2338 * @param conn The DRM connector object
2339 * @param drm_device udev device pointer
2340 * @return 0 on success, -1 on failure
2341 */
2342static int
2343drm_backend_add_connector(struct drm_backend *b, drmModeConnector *conn,
2344 struct udev_device *drm_device)
2345{
2346 int ret;
2347
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002348 if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
2349 ret = drm_writeback_create(b, conn);
2350 if (ret < 0)
2351 weston_log("DRM: failed to create writeback for connector %d.\n",
2352 conn->connector_id);
2353 } else {
2354 ret = drm_head_create(b, conn, drm_device);
2355 if (ret < 0)
2356 weston_log("DRM: failed to create head for connector %d.\n",
2357 conn->connector_id);
2358 }
Leandro Ribeiro72430222020-09-14 17:41:41 -03002359
2360 return ret;
2361}
2362
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002363/** Find all connectors of the fd and create drm_head or drm_writeback objects
2364 * (depending on the type of connector they are) for each of them
2365 *
2366 * These objects are added to the DRM-backend lists of heads and writebacks.
2367 *
2368 * @param b The DRM-backend structure
2369 * @param drm_device udev device pointer
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03002370 * @param resources The DRM resources, it is taken with drmModeGetResources
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002371 * @return 0 on success, -1 on failure
2372 */
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002373static int
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03002374drm_backend_discover_connectors(struct drm_backend *b, struct udev_device *drm_device,
2375 drmModeRes *resources)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002376{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002377 drmModeConnector *conn;
2378 int i, ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002379
Giulio Camuffo954f1832014-10-11 18:27:30 +03002380 b->min_width = resources->min_width;
2381 b->max_width = resources->max_width;
2382 b->min_height = resources->min_height;
2383 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002384
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002385 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002386 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00002387
Leandro Ribeiro70863962020-09-09 13:12:35 -03002388 conn = drmModeGetConnector(b->drm.fd, connector_id);
2389 if (!conn)
2390 continue;
2391
Leandro Ribeiro72430222020-09-14 17:41:41 -03002392 ret = drm_backend_add_connector(b, conn, drm_device);
2393 if (ret < 0)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002394 drmModeFreeConnector(conn);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002395 }
2396
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002397 return 0;
2398}
2399
Leandro Ribeiro99611c82020-09-14 17:19:12 -03002400static bool
2401resources_has_connector(drmModeRes *resources, uint32_t connector_id)
2402{
2403 for (int i = 0; i < resources->count_connectors; i++) {
2404 if (resources->connectors[i] == connector_id)
2405 return true;
2406 }
2407
2408 return false;
2409}
2410
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002411static void
Leandro Ribeiro993920d2020-09-14 17:01:01 -03002412drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002413{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002414 drmModeRes *resources;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002415 drmModeConnector *conn;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002416 struct weston_head *base, *base_next;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002417 struct drm_head *head;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002418 struct drm_writeback *writeback, *writeback_next;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002419 uint32_t connector_id;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002420 int i, ret;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002421
Giulio Camuffo954f1832014-10-11 18:27:30 +03002422 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002423 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002424 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002425 return;
2426 }
2427
Pekka Paalanend2e62422017-09-08 15:48:07 +03002428 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002429 for (i = 0; i < resources->count_connectors; i++) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002430 connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02002431
Leandro Ribeiro70863962020-09-09 13:12:35 -03002432 conn = drmModeGetConnector(b->drm.fd, connector_id);
2433 if (!conn)
2434 continue;
2435
Pekka Paalanend2e62422017-09-08 15:48:07 +03002436 head = drm_head_find_by_connector(b, connector_id);
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002437 writeback = drm_writeback_find_by_connector(b, connector_id);
2438
2439 /* Connector can't be owned by both a head and a writeback, so
2440 * one of the searches must fail. */
2441 assert(head == NULL || writeback == NULL);
2442
Leandro Ribeiro72430222020-09-14 17:41:41 -03002443 if (head)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002444 ret = drm_head_update_info(head, conn);
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002445 else if (writeback)
2446 ret = drm_writeback_update_info(writeback, conn);
Leandro Ribeiro72430222020-09-14 17:41:41 -03002447 else
2448 ret = drm_backend_add_connector(b, conn, drm_device);
2449
2450 if (ret < 0)
2451 drmModeFreeConnector(conn);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002452 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002453
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002454 /* Destroy head objects of connectors (except writeback connectors) that
2455 * have disappeared. */
2456 wl_list_for_each_safe(base, base_next,
Pekka Paalanena0a37462017-08-31 15:41:57 +03002457 &b->compositor->head_list, compositor_link) {
Pekka Paalanena0a37462017-08-31 15:41:57 +03002458 head = to_drm_head(base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002459 connector_id = head->connector.connector_id;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002460
Leandro Ribeiro99611c82020-09-14 17:19:12 -03002461 if (resources_has_connector(resources, connector_id))
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002462 continue;
2463
Pekka Paalanend2e62422017-09-08 15:48:07 +03002464 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002465 head->base.name, connector_id);
Pekka Paalanend2e62422017-09-08 15:48:07 +03002466 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002467 }
2468
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002469 /* Destroy writeback objects of writeback connectors that have
2470 * disappeared. */
2471 wl_list_for_each_safe(writeback, writeback_next,
2472 &b->writeback_connector_list, link) {
2473 connector_id = writeback->connector.connector_id;
2474
2475 if (resources_has_connector(resources, connector_id))
2476 continue;
2477
2478 weston_log("DRM: writeback connector (connector %d) disappeared.\n",
2479 connector_id);
2480 drm_writeback_destroy(writeback);
2481 }
2482
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002483 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002484}
2485
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302486static enum wdrm_connector_property
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002487drm_connector_find_property_by_id(struct drm_connector *connector,
2488 uint32_t property_id)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302489{
2490 int i;
2491 enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
2492
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002493 if (!connector || !property_id)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302494 return WDRM_CONNECTOR__COUNT;
2495
2496 for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002497 if (connector->props[i].prop_id == property_id) {
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302498 prop = (enum wdrm_connector_property) i;
2499 break;
2500 }
2501 return prop;
2502}
2503
2504static void
2505drm_backend_update_conn_props(struct drm_backend *b,
2506 uint32_t connector_id,
2507 uint32_t property_id)
2508{
2509 struct drm_head *head;
2510 enum wdrm_connector_property conn_prop;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302511
2512 head = drm_head_find_by_connector(b, connector_id);
2513 if (!head) {
2514 weston_log("DRM: failed to find head for connector id: %d.\n",
2515 connector_id);
2516 return;
2517 }
2518
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002519 conn_prop = drm_connector_find_property_by_id(&head->connector, property_id);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302520 if (conn_prop >= WDRM_CONNECTOR__COUNT)
2521 return;
2522
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002523 if (drm_connector_update_properties(&head->connector) < 0)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302524 return;
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002525
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302526 if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
2527 weston_head_set_content_protection_status(&head->base,
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002528 drm_head_get_current_protection(head));
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302529 }
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302530}
2531
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002532static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002533udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002534{
David Herrmannd7488c22012-03-11 20:05:21 +01002535 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002536 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002537
2538 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002539 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002540 return 0;
David Herrmann6ac52db2012-03-11 20:05:22 +01002541 val = udev_device_get_property_value(device, "HOTPLUG");
2542 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002543 return 0;
limin.tianaaaff782024-12-20 09:49:25 +00002544 if (val)
2545 weston_log("\n %s %d :HOTPLUG val:%s\n", __FUNCTION__,__LINE__,val);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002546
David Herrmann6ac52db2012-03-11 20:05:22 +01002547 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002548}
2549
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002550static int
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302551udev_event_is_conn_prop_change(struct drm_backend *b,
2552 struct udev_device *device,
2553 uint32_t *connector_id,
2554 uint32_t *property_id)
2555
2556{
2557 const char *val;
2558 int id;
2559
2560 val = udev_device_get_property_value(device, "CONNECTOR");
2561 if (!val || !safe_strtoint(val, &id))
2562 return 0;
2563 else
2564 *connector_id = id;
2565
2566 val = udev_device_get_property_value(device, "PROPERTY");
2567 if (!val || !safe_strtoint(val, &id))
2568 return 0;
2569 else
2570 *property_id = id;
2571
2572 return 1;
2573}
2574
2575static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002576udev_drm_event(int fd, uint32_t mask, void *data)
2577{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002578 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002579 struct udev_device *event;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302580 uint32_t conn_id, prop_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002581
Giulio Camuffo954f1832014-10-11 18:27:30 +03002582 event = udev_monitor_receive_device(b->udev_monitor);
limin.tian930711f2024-11-08 08:11:08 +00002583 udev_event_is_resume(b, event);
limin.tianaaaff782024-12-20 09:49:25 +00002584 if (udev_event_is_hotplug(b, event) && (b->display_enable || b->hdmitx_hdcppwr)) {
leng.fang91856072024-06-07 14:12:54 +08002585#ifdef ENABLE_MODE_POLICY
leng.fang13fd3982024-07-03 19:09:58 +08002586 mode_policy_set_hotplug(AML_WESTON_HOTPLUG_PLUG | AML_WESTON_HOTPLUG_UNPLUG, true);
leng.fang91856072024-06-07 14:12:54 +08002587#endif
limin.tianaaaff782024-12-20 09:49:25 +00002588 if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id)) {
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302589 drm_backend_update_conn_props(b, conn_id, prop_id);
limin.tianaaaff782024-12-20 09:49:25 +00002590 } else {
Leandro Ribeiro993920d2020-09-14 17:01:01 -03002591 drm_backend_update_connectors(b, event);
limin.tianaaaff782024-12-20 09:49:25 +00002592 weston_log("\n %s %d update connectors\n",__FUNCTION__,__LINE__);
2593 }
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302594 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002595
leng.fang32af9fc2024-06-13 11:22:15 +08002596#ifdef BUILD_AML_TV
2597 drm_backend_afr_update(b, udev_event_frame_rate_hint(event),
2598 udev_event_is_vdin_event(event));
2599#endif
2600
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002601 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002602
2603 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002604}
2605
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002606static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002607drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002608{
Armin Krezović545dba62016-08-05 15:54:18 +02002609 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002610 struct weston_head *base, *next;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002611 struct drm_crtc *crtc, *crtc_tmp;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002612 struct drm_writeback *writeback, *writeback_tmp;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002613
leng.fang32af9fc2024-06-13 11:22:15 +08002614#ifdef ENABLE_DRM_HELP
2615 stop_help_worker();
2616#endif
2617
Giulio Camuffo954f1832014-10-11 18:27:30 +03002618 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002619
Giulio Camuffo954f1832014-10-11 18:27:30 +03002620 wl_event_source_remove(b->udev_drm_source);
2621 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002622
Daniel Stoneb57c6a02017-10-05 16:27:21 +01002623 b->shutting_down = true;
2624
Giulio Camuffo954f1832014-10-11 18:27:30 +03002625 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002626
Leandro Ribeirof0149642019-12-18 15:52:18 -03002627 weston_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002628 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002629 weston_compositor_shutdown(ec);
2630
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002631 wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
2632 drm_crtc_destroy(crtc);
2633
Pekka Paalanenc112f002017-08-28 16:27:20 +03002634 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
2635 drm_head_destroy(to_drm_head(base));
2636
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002637 wl_list_for_each_safe(writeback, writeback_tmp,
2638 &b->writeback_connector_list, link)
2639 drm_writeback_destroy(writeback);
2640
Stefan Agnerccf24072019-07-09 22:02:00 +02002641#ifdef BUILD_DRM_GBM
Giulio Camuffo954f1832014-10-11 18:27:30 +03002642 if (b->gbm)
2643 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02002644#endif
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002645
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02002646 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03002647 udev_unref(b->udev);
2648
Marius Vlad7a44ee72021-06-23 16:02:35 +03002649 weston_launcher_close(ec->launcher, b->drm.fd);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002650 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002651
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02002652 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002653 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002654}
2655
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002656static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002657session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002658{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002659 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02002660 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01002661 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002662 struct drm_output *output;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002663 struct drm_crtc *crtc;
leng.fang3e8a4b52024-07-24 14:51:30 +08002664 struct weston_head *head;
limin.tian930711f2024-11-08 08:11:08 +00002665 bool found = false;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002666 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002667 weston_log("activating session\n");
limin.tian930711f2024-11-08 08:11:08 +00002668 udev_input_enable(&b->input);
limin.tianaaaff782024-12-20 09:49:25 +00002669 resume_display(b);
limin.tian930711f2024-11-08 08:11:08 +00002670 weston_compositor_resume_focus(compositor);
Daniel Stonef33e1042016-11-05 08:10:13 +00002671 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002672 weston_compositor_damage_all(compositor);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002673 } else {
2674 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002675 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002676
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002677 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002678
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002679 /* If we have a repaint scheduled (either from a
2680 * pending pageflip or the idle handler), make sure we
2681 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002682 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002683 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002684 * back, we schedule a repaint, which will process
2685 * pending frame callbacks. */
2686
Giulio Camuffo954f1832014-10-11 18:27:30 +03002687 wl_list_for_each(output, &compositor->output_list, base.link) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002688 crtc = output->crtc;
Daniel Stone09a97e22017-03-01 11:34:06 +00002689 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002690 if (output->cursor_plane)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002691 drmModeSetCursor(b->drm.fd, crtc->crtc_id,
Daniel Stone2ba17f42015-05-19 20:02:41 +01002692 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002693 }
2694
leng.fang5ec9b6c2024-07-29 14:25:00 +08002695 if (wl_list_empty(&compositor->output_list)) {
2696 wl_list_for_each(crtc, &b->crtc_list, link)
2697 break;
2698 } else {
2699 output = container_of(compositor->output_list.next,
2700 struct drm_output, base.link);
2701 crtc = output->crtc;
2702 }
2703
2704 if (!crtc)
2705 return;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002706
Daniel Stone085d2b92015-05-21 00:00:57 +01002707 wl_list_for_each(plane, &b->plane_list, link) {
2708 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
2709 continue;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002710 drmModeSetPlane(b->drm.fd, plane->plane_id, crtc->crtc_id,
2711 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01002712 }
2713 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002714}
2715
Robert Beckett8d23ab72019-06-13 16:55:44 +01002716
2717/**
2718 * Handle KMS GPU being added/removed
2719 *
2720 * If the device being added/removed is the KMS device, we activate/deactivate
2721 * the compositor session.
2722 *
2723 * @param compositor The compositor instance.
2724 * @param device The device being added/removed.
2725 * @param added Whether the device is being added (or removed)
2726 */
2727static void
2728drm_device_changed(struct weston_compositor *compositor,
2729 dev_t device, bool added)
2730{
2731 struct drm_backend *b = to_drm_backend(compositor);
2732
Robert Beckett49dc3202019-07-02 16:31:22 +01002733 if (b->drm.fd < 0 || b->drm.devnum != device ||
2734 compositor->session_active == added)
Robert Beckett8d23ab72019-06-13 16:55:44 +01002735 return;
2736
2737 compositor->session_active = added;
2738 wl_signal_emit(&compositor->session_signal, compositor);
2739}
2740
Daniel Stoneefa504f2016-12-19 16:48:20 +00002741/**
2742 * Determines whether or not a device is capable of modesetting. If successful,
2743 * sets b->drm.fd and b->drm.filename to the opened device.
2744 */
2745static bool
2746drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2747{
2748 const char *filename = udev_device_get_devnode(device);
2749 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002750 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002751 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02002752 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002753
2754 if (!filename)
2755 return false;
2756
2757 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
2758 if (fd < 0)
2759 return false;
2760
2761 res = drmModeGetResources(fd);
2762 if (!res)
2763 goto out_fd;
2764
2765 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2766 res->count_encoders <= 0)
2767 goto out_res;
2768
2769 if (sysnum)
2770 id = atoi(sysnum);
2771 if (!sysnum || id < 0) {
2772 weston_log("couldn't get sysnum for device %s\n", filename);
2773 goto out_res;
2774 }
2775
2776 /* We can be called successfully on multiple devices; if we have,
2777 * clean up old entries. */
2778 if (b->drm.fd >= 0)
2779 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2780 free(b->drm.filename);
2781
2782 b->drm.fd = fd;
2783 b->drm.id = id;
2784 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002785 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002786
Sergi Granellceb59812017-03-28 12:44:04 +02002787 drmModeFreeResources(res);
2788
Daniel Stoneefa504f2016-12-19 16:48:20 +00002789 return true;
2790
2791out_res:
2792 drmModeFreeResources(res);
2793out_fd:
2794 weston_launcher_close(b->compositor->launcher, fd);
2795 return false;
2796}
2797
David Herrmann0af066f2012-10-29 19:21:16 +01002798/*
2799 * Find primary GPU
2800 * Some systems may have multiple DRM devices attached to a single seat. This
2801 * function loops over all devices and tries to find a PCI device with the
2802 * boot_vga sysfs attribute set to 1.
2803 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00002804 * Devices are also vetted to make sure they are are capable of modesetting,
2805 * rather than pure render nodes (GPU with no display), or pure
2806 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01002807 */
2808static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002809find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002810{
2811 struct udev_enumerate *e;
2812 struct udev_list_entry *entry;
2813 const char *path, *device_seat, *id;
2814 struct udev_device *device, *drm_device, *pci;
2815
Giulio Camuffo954f1832014-10-11 18:27:30 +03002816 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002817 udev_enumerate_add_match_subsystem(e, "drm");
2818 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2819
2820 udev_enumerate_scan_devices(e);
2821 drm_device = NULL;
2822 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00002823 bool is_boot_vga = false;
2824
David Herrmann0af066f2012-10-29 19:21:16 +01002825 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002826 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002827 if (!device)
2828 continue;
2829 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2830 if (!device_seat)
2831 device_seat = default_seat;
2832 if (strcmp(device_seat, seat)) {
2833 udev_device_unref(device);
2834 continue;
2835 }
2836
2837 pci = udev_device_get_parent_with_subsystem_devtype(device,
2838 "pci", NULL);
2839 if (pci) {
2840 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00002841 if (id && !strcmp(id, "1"))
2842 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01002843 }
2844
Daniel Stoneefa504f2016-12-19 16:48:20 +00002845 /* If we already have a modesetting-capable device, and this
2846 * device isn't our boot-VGA device, we aren't going to use
2847 * it. */
2848 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01002849 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002850 continue;
2851 }
2852
2853 /* Make sure this device is actually capable of modesetting;
2854 * if this call succeeds, b->drm.{fd,filename} will be set,
2855 * and any old values freed. */
2856 if (!drm_device_is_kms(b, device)) {
2857 udev_device_unref(device);
2858 continue;
2859 }
2860
2861 /* There can only be one boot_vga device, and we try to use it
2862 * at all costs. */
2863 if (is_boot_vga) {
2864 if (drm_device)
2865 udev_device_unref(drm_device);
2866 drm_device = device;
2867 break;
2868 }
2869
2870 /* Per the (!is_boot_vga && drm_device) test above, we only
2871 * trump existing saved devices with boot-VGA devices, so if
2872 * we end up here, this must be the first device we've seen. */
2873 assert(!drm_device);
2874 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01002875 }
2876
Daniel Stoneefa504f2016-12-19 16:48:20 +00002877 /* If we're returning a device to use, we must have an open FD for
2878 * it. */
2879 assert(!!drm_device == (b->drm.fd >= 0));
2880
David Herrmann0af066f2012-10-29 19:21:16 +01002881 udev_enumerate_unref(e);
2882 return drm_device;
2883}
2884
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002885static struct udev_device *
2886open_specific_drm_device(struct drm_backend *b, const char *name)
2887{
2888 struct udev_device *device;
2889
2890 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2891 if (!device) {
2892 weston_log("ERROR: could not open DRM device '%s'\n", name);
2893 return NULL;
2894 }
2895
2896 if (!drm_device_is_kms(b, device)) {
2897 udev_device_unref(device);
2898 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2899 return NULL;
2900 }
2901
2902 /* If we're returning a device to use, we must have an open FD for
2903 * it. */
2904 assert(b->drm.fd >= 0);
2905
2906 return device;
2907}
2908
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002909static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002910planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2911 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002912{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002913 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002914
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002915 switch (key) {
2916 case KEY_C:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002917 b->cursors_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002918 break;
2919 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01002920 /* We don't support overlay-plane usage with legacy KMS. */
2921 if (b->atomic_modeset)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002922 b->sprites_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002923 break;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002924 default:
2925 break;
2926 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002927}
2928
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002929#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002930static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002931recorder_destroy(struct drm_output *output)
2932{
2933 vaapi_recorder_destroy(output->recorder);
2934 output->recorder = NULL;
2935
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302936 weston_output_disable_planes_decr(&output->base);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002937
2938 wl_list_remove(&output->recorder_frame_listener.link);
2939 weston_log("[libva recorder] done\n");
2940}
2941
2942static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002943recorder_frame_notify(struct wl_listener *listener, void *data)
2944{
2945 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002946 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002947 int fd, ret;
2948
2949 output = container_of(listener, struct drm_output,
2950 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02002951 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002952
2953 if (!output->recorder)
2954 return;
2955
Daniel Stonee2e80132018-01-16 15:37:33 +00002956 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002957 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002958 DRM_CLOEXEC, &fd);
2959 if (ret) {
2960 weston_log("[libva recorder] "
2961 "failed to create prime fd for front buffer\n");
2962 return;
2963 }
2964
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002965 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002966 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002967 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002968 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002969 recorder_destroy(output);
2970 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002971}
2972
2973static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002974create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002975 const char *filename)
2976{
2977 int fd;
2978 drm_magic_t magic;
2979
Giulio Camuffo954f1832014-10-11 18:27:30 +03002980 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002981 if (fd < 0)
2982 return NULL;
2983
2984 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002985 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002986
2987 return vaapi_recorder_create(fd, width, height, filename);
2988}
2989
2990static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002991recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2992 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002993{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002994 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002995 struct drm_output *output;
2996 int width, height;
2997
Giulio Camuffo954f1832014-10-11 18:27:30 +03002998 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002999 struct drm_output, base.link);
3000
3001 if (!output->recorder) {
Stefan Agner4a18f302019-10-20 18:25:42 +02003002 if (output->gbm_format != DRM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03003003 weston_log("failed to start vaapi recorder: "
3004 "output format not supported\n");
3005 return;
3006 }
3007
Hardeningff39efa2013-09-18 23:56:35 +02003008 width = output->base.current_mode->width;
3009 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03003010
3011 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03003012 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03003013 if (!output->recorder) {
3014 weston_log("failed to create vaapi recorder\n");
3015 return;
3016 }
3017
Ankit Nautiyal93dde242019-07-08 11:46:42 +05303018 weston_output_disable_planes_incr(&output->base);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03003019
3020 output->recorder_frame_listener.notify = recorder_frame_notify;
3021 wl_signal_add(&output->base.frame_signal,
3022 &output->recorder_frame_listener);
3023
3024 weston_output_schedule_repaint(&output->base);
3025
3026 weston_log("[libva recorder] initialized\n");
3027 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03003028 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03003029 }
3030}
3031#else
3032static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02003033recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
3034 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03003035{
3036 weston_log("Compiled without libva support\n");
3037}
3038#endif
3039
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003040
Armin Krezović08368132016-09-30 14:11:05 +02003041static const struct weston_drm_output_api api = {
3042 drm_output_set_mode,
3043 drm_output_set_gbm_format,
3044 drm_output_set_seat,
3045};
3046
Giulio Camuffo954f1832014-10-11 18:27:30 +03003047static struct drm_backend *
3048drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003049 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003050{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003051 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01003052 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003053 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003054 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04003055 const char *session_seat;
Leandro Ribeiro54293022021-10-12 14:48:36 -03003056 struct weston_drm_format_array *scanout_formats;
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003057 drmModeRes *res;
Armin Krezović08368132016-09-30 14:11:05 +02003058 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003059
nerdopolisb16c4ac2018-06-29 08:17:46 -04003060 session_seat = getenv("XDG_SEAT");
3061 if (session_seat)
3062 seat_id = session_seat;
3063
3064 if (config->seat_id)
3065 seat_id = config->seat_id;
3066
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003067 weston_log("initializing drm backend\n");
3068
Giulio Camuffo954f1832014-10-11 18:27:30 +03003069 b = zalloc(sizeof *b);
3070 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003071 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003072
Daniel Stone6020f472018-02-05 15:46:20 +00003073 b->state_invalid = true;
leng.fang32af9fc2024-06-13 11:22:15 +08003074 b->allow_modeset = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003075 b->drm.fd = -1;
leng.fang9cf09e22024-07-17 20:01:11 +08003076 b->display_enable = 1;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003077
leng.fang32af9fc2024-06-13 11:22:15 +08003078#ifdef BUILD_AML_TV
3079 b->vdin_detect_fd = -1;
3080#endif
3081
Giulio Camuffo954f1832014-10-11 18:27:30 +03003082 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003083 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00003084 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02003085 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003086
Leandro Ribeiro172afc22019-12-26 16:23:43 -03003087 b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
3088 "Debug messages from DRM/KMS backend\n",
3089 NULL, NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003090
Pekka Paalanen7da9a382017-08-30 11:29:49 +03003091 compositor->backend = &b->base;
3092
Stefan Agner0bfebeb2019-07-08 00:30:44 +02003093 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003094 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003095
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003096 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003097 compositor->launcher = weston_launcher_connect(compositor, config->tty,
3098 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003099 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02003100 weston_log("fatal: drm backend should be run using "
3101 "weston-launch binary, or your system should "
3102 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003103 goto err_compositor;
3104 }
3105
Giulio Camuffo954f1832014-10-11 18:27:30 +03003106 b->udev = udev_new();
3107 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003108 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003109 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003110 }
3111
Giulio Camuffo954f1832014-10-11 18:27:30 +03003112 b->session_listener.notify = session_notify;
3113 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003114
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03003115 if (config->specific_device)
3116 drm_device = open_specific_drm_device(b, config->specific_device);
3117 else
3118 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003119 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003120 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003121 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003122 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003123
Daniel Stoneefa504f2016-12-19 16:48:20 +00003124 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003125 weston_log("failed to initialize kms\n");
3126 goto err_udev_dev;
3127 }
3128
Giulio Camuffo954f1832014-10-11 18:27:30 +03003129 if (b->use_pixman) {
3130 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003131 weston_log("failed to initialize pixman renderer\n");
3132 goto err_udev_dev;
3133 }
3134 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003135 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003136 weston_log("failed to initialize egl\n");
3137 goto err_udev_dev;
3138 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003139 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003140
Giulio Camuffo954f1832014-10-11 18:27:30 +03003141 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003142 b->base.repaint_begin = drm_repaint_begin;
3143 b->base.repaint_flush = drm_repaint_flush;
3144 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03003145 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01003146 b->base.device_changed = drm_device_changed;
Marius Vlad81bada52019-11-11 00:27:17 +02003147 b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003148
leng.fang32af9fc2024-06-13 11:22:15 +08003149 drm_add_aml_callback(b);
Bob Ham91880f12016-01-12 10:21:47 +00003150 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003151
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003152 res = drmModeGetResources(b->drm.fd);
3153 if (!res) {
3154 weston_log("Failed to get drmModeRes\n");
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03003155 goto err_udev_dev;
3156 }
3157
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003158 wl_list_init(&b->crtc_list);
3159 if (drm_backend_create_crtc_list(b, res) == -1) {
3160 weston_log("Failed to create CRTC list for DRM-backend\n");
3161 goto err_create_crtc_list;
3162 }
3163
Daniel Stone085d2b92015-05-21 00:00:57 +01003164 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003165 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003166
Giulio Camuffo954f1832014-10-11 18:27:30 +03003167 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03003168 compositor, b->udev, seat_id,
3169 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003170 weston_log("failed to create input devices\n");
3171 goto err_sprite;
3172 }
3173
leng.fang32af9fc2024-06-13 11:22:15 +08003174#ifdef ENABLE_DRM_HELP
3175 weston_log("drm start_help_worker \n");
3176 start_help_worker(b->drm.fd, b->atomic_modeset);
3177#endif
3178
leng.fang91856072024-06-07 14:12:54 +08003179#ifdef ENABLE_MODE_POLICY
leng.fang69a93e32024-08-08 16:31:01 +08003180 mode_policy_set_state(NULL, AML_WESTON_HOTPLUG_BOOT, true);
leng.fang91856072024-06-07 14:12:54 +08003181#endif
3182
Leandro Ribeiro96bef052020-09-09 15:23:49 -03003183 wl_list_init(&b->writeback_connector_list);
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003184 if (drm_backend_discover_connectors(b, drm_device, res) < 0) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03003185 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003186 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003187 }
3188
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003189 drmModeFreeResources(res);
3190
Marius Vlade83e7502019-10-29 17:29:37 +02003191 /* 'compute' faked zpos values in case HW doesn't expose any */
3192 drm_backend_create_faked_zpos(b);
3193
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003194 /* A this point we have some idea of whether or not we have a working
3195 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003196 if (!b->cursors_are_broken)
3197 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003198
Giulio Camuffo954f1832014-10-11 18:27:30 +03003199 loop = wl_display_get_event_loop(compositor->wl_display);
3200 b->drm_source =
3201 wl_event_loop_add_fd(loop, b->drm.fd,
3202 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003203
limin.tianaaaff782024-12-20 09:49:25 +00003204 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "kernel");
Giulio Camuffo954f1832014-10-11 18:27:30 +03003205 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05003206 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003207 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003208 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003209 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
limin.tianaaaff782024-12-20 09:49:25 +00003210 "amhdmitx", NULL);
3211 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003212 "drm", NULL);
leng.fang32af9fc2024-06-13 11:22:15 +08003213#ifdef BUILD_AML_TV
3214 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
3215 "vdin", NULL);
3216 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
3217 "framerate_adapter", NULL);
3218#endif
limin.tianaaaff782024-12-20 09:49:25 +00003219
leng.fang32af9fc2024-06-13 11:22:15 +08003220
Giulio Camuffo954f1832014-10-11 18:27:30 +03003221 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003222 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003223 udev_monitor_get_fd(b->udev_monitor),
3224 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003225
Giulio Camuffo954f1832014-10-11 18:27:30 +03003226 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003227 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003228 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003229 }
3230
Daniel Stonea96b93c2012-06-22 14:04:37 +01003231 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003232
Giulio Camuffo954f1832014-10-11 18:27:30 +03003233 weston_compositor_add_debug_binding(compositor, KEY_O,
3234 planes_binding, b);
3235 weston_compositor_add_debug_binding(compositor, KEY_C,
3236 planes_binding, b);
3237 weston_compositor_add_debug_binding(compositor, KEY_V,
3238 planes_binding, b);
3239 weston_compositor_add_debug_binding(compositor, KEY_Q,
3240 recorder_binding, b);
3241 weston_compositor_add_debug_binding(compositor, KEY_W,
3242 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003243
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003244 if (compositor->renderer->import_dmabuf) {
3245 if (linux_dmabuf_setup(compositor) < 0)
3246 weston_log("Error: initializing dmabuf "
3247 "support failed.\n");
Leandro Ribeiro54293022021-10-12 14:48:36 -03003248 if (compositor->default_dmabuf_feedback) {
3249 /* We were able to create the compositor's default
3250 * dma-buf feedback in the renderer, that means that the
3251 * table was already created and populated with
3252 * renderer's format/modifier pairs. So now we must
3253 * compute the scanout formats indices in the table */
3254 scanout_formats = get_scanout_formats(b);
3255 if (!scanout_formats)
3256 goto err_udev_monitor;
3257 ret = weston_dmabuf_feedback_format_table_set_scanout_indices(compositor->dmabuf_feedback_format_table,
3258 scanout_formats);
3259 weston_drm_format_array_fini(scanout_formats);
Daniel Stonef5086032021-12-06 16:52:19 +00003260 free(scanout_formats);
Leandro Ribeiro54293022021-10-12 14:48:36 -03003261 if (ret < 0)
3262 goto err_udev_monitor;
3263 }
Marius Vladebd10e52019-11-16 19:22:48 +02003264 if (weston_direct_display_setup(compositor) < 0)
3265 weston_log("Error: initializing direct-display "
3266 "support failed.\n");
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003267 }
3268
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003269 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
3270 if (linux_explicit_synchronization_setup(compositor) < 0)
3271 weston_log("Error: initializing explicit "
3272 " synchronization support failed.\n");
3273 }
3274
Ankit Nautiyala344fe32019-05-14 18:36:08 +05303275 if (b->atomic_modeset)
3276 if (weston_compositor_enable_content_protection(compositor) < 0)
3277 weston_log("Error: initializing content-protection "
3278 "support failed.\n");
3279
Armin Krezović08368132016-09-30 14:11:05 +02003280 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
3281 &api, sizeof(api));
3282
3283 if (ret < 0) {
3284 weston_log("Failed to register output API.\n");
3285 goto err_udev_monitor;
3286 }
3287
Stefan Agner3654c672019-07-09 00:50:30 +02003288 ret = drm_backend_init_virtual_output_api(compositor);
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003289 if (ret < 0) {
3290 weston_log("Failed to register virtual output API.\n");
3291 goto err_udev_monitor;
3292 }
leng.fang91856072024-06-07 14:12:54 +08003293
leng.fang32af9fc2024-06-13 11:22:15 +08003294#ifdef ENABLE_DRM_HELP
leng.fangc0af1fa2024-08-13 17:54:42 +08003295 aml_drm_backend_create(b);
leng.fang32af9fc2024-06-13 11:22:15 +08003296 help_set_printinfo_function(compositor, weston_print_info);
3297#endif
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003298
leng.fang91856072024-06-07 14:12:54 +08003299#ifdef ENABLE_MODE_POLICY
3300 weston_start_update_env_thread();
3301#endif
3302
Giulio Camuffo954f1832014-10-11 18:27:30 +03003303 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003304
3305err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003306 wl_event_source_remove(b->udev_drm_source);
3307 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003308err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003309 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003310err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003311 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003312err_sprite:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003313 destroy_sprites(b);
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003314err_create_crtc_list:
3315 drmModeFreeResources(res);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003316err_udev_dev:
3317 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003318err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003319 udev_unref(b->udev);
Marius Vlad5130a8c2020-07-30 14:47:32 +03003320err_launcher:
3321 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003322err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003323 weston_compositor_shutdown(compositor);
Marius Vladd171c7b2021-04-01 00:12:00 +03003324#ifdef BUILD_DRM_GBM
3325 if (b->gbm)
3326 gbm_device_destroy(b->gbm);
3327#endif
Giulio Camuffo954f1832014-10-11 18:27:30 +03003328 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003329 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003330}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003331
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003332static void
3333config_init_to_defaults(struct weston_drm_backend_config *config)
3334{
Pekka Paalanendee412d2018-04-23 11:44:58 +02003335 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003336}
3337
Giulio Camuffo954f1832014-10-11 18:27:30 +03003338WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01003339weston_backend_init(struct weston_compositor *compositor,
3340 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003341{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003342 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003343 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003344
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003345 if (config_base == NULL ||
3346 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3347 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3348 weston_log("drm backend config structure is invalid\n");
3349 return -1;
3350 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02003351
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003352 config_init_to_defaults(&config);
3353 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003354
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003355 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003356 if (b == NULL)
3357 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003358
Giulio Camuffo954f1832014-10-11 18:27:30 +03003359 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003360}