blob: cd4639e800d467b632481017b8679d4cc180977c [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Pekka Paalanen925788f2018-04-19 14:20:01 +03004 * Copyright © 2017, 2018 Collabora, Ltd.
5 * Copyright © 2017, 2018 General Electric Company
Pekka Paalanen62a94362018-09-26 14:33:36 +03006 * Copyright (c) 2018 DisplayLink (UK) Ltd.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07008 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040015 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070016 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040028 */
29
Daniel Stonec228e232013-05-22 18:03:19 +030030#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040031
Jesse Barnes58ef3792012-02-23 09:45:49 -050032#include <errno.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030033#include <stdint.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010035#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040036#include <string.h>
37#include <fcntl.h>
38#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040039#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070040#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030041#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020042#include <sys/mman.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030043#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040044
Benjamin Franzkec649a922011-03-02 11:56:04 +010045#include <xf86drm.h>
46#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050047#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010048
Pekka Paalanen33156972012-08-03 13:30:30 -040049#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020050
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020051#include <libweston/libweston.h>
Pekka Paalanen75710272019-03-29 16:39:12 +020052#include <libweston/backend-drm.h>
Marius Vladc901e892019-06-21 22:49:18 +030053#include <libweston/weston-log.h>
Daniel Stonedd1bc502019-06-17 12:13:46 +010054#include "drm-internal.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070055#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020056#include "shared/timespec-util.h"
Ankit Nautiyala344fe32019-05-14 18:36:08 +053057#include "shared/string-helpers.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020058#include "pixman-renderer.h"
Daniel Stone0b70fa42017-04-04 17:54:23 +010059#include "pixel-formats.h"
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070060#include "libbacklight.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100061#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010062#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030063#include "vaapi-recorder.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020064#include "presentation-time-server-protocol.h"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030065#include "linux-dmabuf.h"
Micah Fedkec8890122017-02-01 15:28:23 -050066#include "linux-dmabuf-unstable-v1-server-protocol.h"
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030067#include "linux-explicit-synchronization.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040068
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050069static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -040070
Daniel Stone087ddf02017-02-14 17:51:30 +000071static void
Marius Vlade83e7502019-10-29 17:29:37 +020072drm_backend_create_faked_zpos(struct drm_backend *b)
73{
74 struct drm_plane *plane;
75 uint64_t zpos = 0ULL;
76 uint64_t zpos_min_primary;
77 uint64_t zpos_min_overlay;
78 uint64_t zpos_min_cursor;
79
80 zpos_min_primary = zpos;
81 wl_list_for_each(plane, &b->plane_list, link) {
82 /* if the property is there, bail out sooner */
83 if (plane->props[WDRM_PLANE_ZPOS].prop_id != 0)
84 return;
85
86 if (plane->type != WDRM_PLANE_TYPE_PRIMARY)
87 continue;
88 zpos++;
89 }
90
91 zpos_min_overlay = zpos;
92 wl_list_for_each(plane, &b->plane_list, link) {
93 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
94 continue;
95 zpos++;
96 }
97
98 zpos_min_cursor = zpos;
99 wl_list_for_each(plane, &b->plane_list, link) {
100 if (plane->type != WDRM_PLANE_TYPE_CURSOR)
101 continue;
102 zpos++;
103 }
104
105 drm_debug(b, "[drm-backend] zpos property not found. "
106 "Using invented immutable zpos values:\n");
107 /* assume that invented zpos values are immutable */
108 wl_list_for_each(plane, &b->plane_list, link) {
109 if (plane->type == WDRM_PLANE_TYPE_PRIMARY) {
110 plane->zpos_min = zpos_min_primary;
111 plane->zpos_max = zpos_min_primary;
112 } else if (plane->type == WDRM_PLANE_TYPE_OVERLAY) {
113 plane->zpos_min = zpos_min_overlay;
114 plane->zpos_max = zpos_min_overlay;
115 } else if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
116 plane->zpos_min = zpos_min_cursor;
117 plane->zpos_max = zpos_min_cursor;
118 }
119 drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
120 "zpos_max %"PRIu64"\n",
121 drm_output_get_plane_type_name(plane),
122 plane->plane_id, plane->zpos_min, plane->zpos_max);
123 }
124}
125
126static void
Daniel Stone087ddf02017-02-14 17:51:30 +0000127wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
128{
129 uint32_t *pos, *end;
130
131 end = (uint32_t *) ((char *) array->data + array->size);
132
133 wl_array_for_each(pos, array) {
134 if (*pos != elm)
135 continue;
136
137 array->size -= sizeof(*pos);
138 if (pos + 1 == end)
139 break;
140
141 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
142 break;
143 }
144}
145
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000146static int
147pageflip_timeout(void *data) {
148 /*
149 * Our timer just went off, that means we're not receiving drm
150 * page flip events anymore for that output. Let's gracefully exit
151 * weston with a return value so devs can debug what's going on.
152 */
153 struct drm_output *output = data;
154 struct weston_compositor *compositor = output->base.compositor;
155
156 weston_log("Pageflip timeout reached on output %s, your "
157 "driver is probably buggy! Exiting.\n",
158 output->base.name);
159 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
160
161 return 0;
162}
163
164/* Creates the pageflip timer. Note that it isn't armed by default */
165static int
166drm_output_pageflip_timer_create(struct drm_output *output)
167{
168 struct wl_event_loop *loop = NULL;
169 struct weston_compositor *ec = output->base.compositor;
170
171 loop = wl_display_get_event_loop(ec->wl_display);
172 assert(loop);
173 output->pageflip_timer = wl_event_loop_add_timer(loop,
174 pageflip_timeout,
175 output);
176
177 if (output->pageflip_timer == NULL) {
Antonio Borneo39578632019-04-26 23:57:31 +0200178 weston_log("creating drm pageflip timer failed: %s\n",
179 strerror(errno));
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000180 return -1;
181 }
182
183 return 0;
184}
185
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000186static void
187drm_output_destroy(struct weston_output *output_base);
188
Daniel Stone5ff289a2017-10-07 12:59:02 +0100189/**
190 * Returns true if the plane can be used on the given output for its current
191 * repaint cycle.
192 */
Daniel Stonee404b722019-06-22 18:40:31 +0100193bool
Daniel Stone5ff289a2017-10-07 12:59:02 +0100194drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500195{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100196 assert(plane->state_cur);
197
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900198 if (output->virtual)
199 return false;
200
Daniel Stone5ff289a2017-10-07 12:59:02 +0100201 /* The plane still has a request not yet completed by the kernel. */
202 if (!plane->state_cur->complete)
203 return false;
204
205 /* The plane is still active on another output. */
206 if (plane->state_cur->output && plane->state_cur->output != output)
207 return false;
208
209 /* Check whether the plane can be used with this CRTC; possible_crtcs
210 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300211 return !!(plane->possible_crtcs & (1 << output->crtc->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500212}
213
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300214struct drm_crtc *
215drm_crtc_find(struct drm_backend *b, uint32_t crtc_id)
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000216{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300217 struct drm_crtc *crtc;
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000218
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300219 wl_list_for_each(crtc, &b->crtc_list, link) {
220 if (crtc->crtc_id == crtc_id)
221 return crtc;
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000222 }
223
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000224 return NULL;
225}
226
Daniel Stone4c2fc702019-06-18 11:12:07 +0100227struct drm_head *
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300228drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
229{
230 struct weston_head *base;
231 struct drm_head *head;
232
233 wl_list_for_each(base,
234 &backend->compositor->head_list, compositor_link) {
235 head = to_drm_head(base);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300236 if (head->connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300237 return head;
238 }
239
240 return NULL;
241}
242
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000243/**
Daniel Stonea08512f2016-11-08 17:46:10 +0000244 * Get output state to disable output
245 *
246 * Returns a pointer to an output_state object which can be used to disable
247 * an output (e.g. DPMS off).
248 *
249 * @param pending_state The pending state object owning this update
250 * @param output The output to disable
251 * @returns A drm_output_state to disable the output
252 */
253static struct drm_output_state *
254drm_output_get_disable_state(struct drm_pending_state *pending_state,
255 struct drm_output *output)
256{
257 struct drm_output_state *output_state;
258
259 output_state = drm_output_state_duplicate(output->state_cur,
260 pending_state,
261 DRM_OUTPUT_STATE_CLEAR_PLANES);
262 output_state->dpms = WESTON_DPMS_OFF;
263
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530264 output_state->protection = WESTON_HDCP_DISABLE;
265
Daniel Stonea08512f2016-11-08 17:46:10 +0000266 return output_state;
267}
268
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000269
270/**
271 * Mark a drm_output_state (the output's last state) as complete. This handles
272 * any post-completion actions such as updating the repaint timer, disabling the
273 * output, and finally freeing the state.
274 */
Daniel Stone4c2fc702019-06-18 11:12:07 +0100275void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000276drm_output_update_complete(struct drm_output *output, uint32_t flags,
277 unsigned int sec, unsigned int usec)
278{
Daniel Stonea08512f2016-11-08 17:46:10 +0000279 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +0000280 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000281 struct timespec ts;
282
283 /* Stop the pageflip timer instead of rearming it here */
284 if (output->pageflip_timer)
285 wl_event_source_timer_update(output->pageflip_timer, 0);
286
Daniel Stonebc15f682016-11-14 16:57:01 +0000287 wl_list_for_each(ps, &output->state_cur->plane_list, link)
288 ps->complete = true;
289
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000290 drm_output_state_free(output->state_last);
291 output->state_last = NULL;
292
293 if (output->destroy_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100294 output->destroy_pending = false;
295 output->disable_pending = false;
296 output->dpms_off_pending = false;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000297 drm_output_destroy(&output->base);
298 return;
299 } else if (output->disable_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100300 output->disable_pending = false;
301 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +0000302 weston_output_disable(&output->base);
303 return;
304 } else if (output->dpms_off_pending) {
305 struct drm_pending_state *pending = drm_pending_state_alloc(b);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100306 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +0000307 drm_output_get_disable_state(pending, output);
308 drm_pending_state_apply_sync(pending);
Michael Olbrichd70e7122020-08-06 09:57:54 +0200309 }
310 if (output->state_cur->dpms == WESTON_DPMS_OFF &&
311 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
Daniel Stonea08512f2016-11-08 17:46:10 +0000312 /* DPMS can happen to us either in the middle of a repaint
313 * cycle (when we have painted fresh content, only to throw it
314 * away for DPMS off), or at any other random point. If the
315 * latter is true, then we cannot go through finish_frame,
316 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000317 return;
318 }
319
320 ts.tv_sec = sec;
321 ts.tv_nsec = usec * 1000;
322 weston_output_finish_frame(&output->base, &ts, flags);
323
324 /* We can't call this from frame_notify, because the output's
325 * repaint needed flag is cleared just after that */
326 if (output->recorder)
327 weston_output_schedule_repaint(&output->base);
328}
329
Daniel Stone95d48a22017-04-04 17:54:30 +0100330static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000331drm_output_render_pixman(struct drm_output_state *state,
332 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200333{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000334 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200335 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200336
337 output->current_image ^= 1;
338
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200339 pixman_renderer_output_set_buffer(&output->base,
340 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200341 pixman_renderer_output_set_hw_extra_damage(&output->base,
342 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200343
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200344 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200345
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200346 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +0100347
348 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200349}
350
Stefan Agner3654c672019-07-09 00:50:30 +0200351void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000352drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200353{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000354 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300355 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +0000356 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +0000357 struct drm_plane *scanout_plane = output->scanout_plane;
Scott Anderson15c603c2020-06-02 17:39:43 +1200358 struct drm_property_info *damage_info =
359 &scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
Armin Krezović545dba62016-08-05 15:54:18 +0200360 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +0100361 struct drm_fb *fb;
Scott Anderson15c603c2020-06-02 17:39:43 +1200362 pixman_region32_t scanout_damage;
363 pixman_box32_t *rects;
364 int n_rects;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200365
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100366 /* If we already have a client buffer promoted to scanout, then we don't
367 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +0000368 scanout_state = drm_output_state_get_plane(state,
369 output->scanout_plane);
370 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100371 return;
372
Daniel Stone98d75e12020-03-06 11:03:14 +0000373 /*
374 * If we don't have any damage on the primary plane, and we already
375 * have a renderer buffer active, we can reuse it; else we pass
376 * the damaged region into the renderer to re-render the affected
377 * area.
378 */
Daniel Stonee95169b2016-11-14 17:46:59 +0000379 if (!pixman_region32_not_empty(damage) &&
380 scanout_plane->state_cur->fb &&
381 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
Daniel Stone98d75e12020-03-06 11:03:14 +0000382 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
Daniel Stonee95169b2016-11-14 17:46:59 +0000383 fb = drm_fb_ref(scanout_plane->state_cur->fb);
384 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000385 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000386 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000387 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000388 }
Daniel Stone95d48a22017-04-04 17:54:30 +0100389
Daniel Stonee2e80132018-01-16 15:37:33 +0000390 if (!fb) {
391 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +0100392 return;
Daniel Stonee2e80132018-01-16 15:37:33 +0000393 }
394
395 scanout_state->fb = fb;
396 scanout_state->output = output;
397
398 scanout_state->src_x = 0;
399 scanout_state->src_y = 0;
Daniel Stonef9a61622020-03-06 11:07:15 +0000400 scanout_state->src_w = fb->width << 16;
401 scanout_state->src_h = fb->height << 16;
Daniel Stonee2e80132018-01-16 15:37:33 +0000402
403 scanout_state->dest_x = 0;
404 scanout_state->dest_y = 0;
Daniel Stonef9a61622020-03-06 11:07:15 +0000405 scanout_state->dest_w = output->base.current_mode->width;
406 scanout_state->dest_h = output->base.current_mode->height;
Daniel Stonee2e80132018-01-16 15:37:33 +0000407
Scott Anderson15c603c2020-06-02 17:39:43 +1200408 pixman_region32_subtract(&c->primary_plane.damage,
409 &c->primary_plane.damage, damage);
410
411 /* Don't bother calculating plane damage if the plane doesn't support it */
412 if (damage_info->prop_id == 0)
413 return;
414
415 pixman_region32_init(&scanout_damage);
416 pixman_region32_copy(&scanout_damage, damage);
417
Deepak Rawat46a1c722018-07-24 14:13:34 -0700418 if (output->base.zoom.active) {
Scott Anderson15c603c2020-06-02 17:39:43 +1200419 weston_matrix_transform_region(&scanout_damage,
Deepak Rawat46a1c722018-07-24 14:13:34 -0700420 &output->base.matrix,
Scott Anderson15c603c2020-06-02 17:39:43 +1200421 &scanout_damage);
Deepak Rawat46a1c722018-07-24 14:13:34 -0700422 } else {
Scott Anderson15c603c2020-06-02 17:39:43 +1200423 pixman_region32_translate(&scanout_damage,
Deepak Rawat46a1c722018-07-24 14:13:34 -0700424 -output->base.x, -output->base.y);
425 weston_transformed_region(output->base.width,
426 output->base.height,
427 output->base.transform,
428 output->base.current_scale,
Scott Anderson15c603c2020-06-02 17:39:43 +1200429 &scanout_damage,
430 &scanout_damage);
Deepak Rawat46a1c722018-07-24 14:13:34 -0700431 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200432
Scott Anderson15c603c2020-06-02 17:39:43 +1200433 assert(scanout_state->damage_blob_id == 0);
434
435 rects = pixman_region32_rectangles(&scanout_damage, &n_rects);
436
437 /*
438 * If this function fails, the blob id should still be 0.
439 * This tells the kernel there is no damage information, which means
440 * that it will consider the whole plane damaged. While this may
441 * affect efficiency, it should still produce correct results.
442 */
443 drmModeCreatePropertyBlob(b->drm.fd, rects,
444 sizeof(*rects) * n_rects,
445 &scanout_state->damage_blob_id);
446
447 pixman_region32_fini(&scanout_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200448}
449
Daniel Stonea08512f2016-11-08 17:46:10 +0000450static int
451drm_output_repaint(struct weston_output *output_base,
452 pixman_region32_t *damage,
453 void *repaint_data)
454{
455 struct drm_pending_state *pending_state = repaint_data;
456 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +0000457 struct drm_output_state *state = NULL;
458 struct drm_plane_state *scanout_state;
459
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900460 assert(!output->virtual);
461
Daniel Stonea08512f2016-11-08 17:46:10 +0000462 if (output->disable_pending || output->destroy_pending)
463 goto err;
464
465 assert(!output->state_last);
466
467 /* If planes have been disabled in the core, we might not have
468 * hit assign_planes at all, so might not have valid output state
469 * here. */
470 state = drm_pending_state_get_output(pending_state, output);
471 if (!state)
472 state = drm_output_state_duplicate(output->state_cur,
473 pending_state,
474 DRM_OUTPUT_STATE_CLEAR_PLANES);
475 state->dpms = WESTON_DPMS_ON;
476
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530477 if (output_base->allow_protection)
478 state->protection = output_base->desired_protection;
479 else
480 state->protection = WESTON_HDCP_DISABLE;
481
Daniel Stonea08512f2016-11-08 17:46:10 +0000482 drm_output_render(state, damage);
483 scanout_state = drm_output_state_get_plane(state,
484 output->scanout_plane);
485 if (!scanout_state || !scanout_state->fb)
486 goto err;
487
Daniel Stonea08512f2016-11-08 17:46:10 +0000488 return 0;
489
490err:
491 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +0200492 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400493}
494
Daniel Stone4c2fc702019-06-18 11:12:07 +0100495/* Determine the type of vblank synchronization to use for the output.
496 *
497 * The pipe parameter indicates which CRTC is in use. Knowing this, we
498 * can determine which vblank sequence type to use for it. Traditional
499 * cards had only two CRTCs, with CRTC 0 using no special flags, and
500 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
501 * parameter indicates this.
502 *
503 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
504 * 0-31. If this is non-zero it indicates we're dealing with a
505 * multi-gpu situation and we need to calculate the vblank sync
506 * using DRM_BLANK_HIGH_CRTC_MASK.
507 */
508static unsigned int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300509drm_waitvblank_pipe(struct drm_crtc *crtc)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100510{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300511 if (crtc->pipe > 1)
512 return (crtc->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
Daniel Stone4c2fc702019-06-18 11:12:07 +0100513 DRM_VBLANK_HIGH_CRTC_MASK;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300514 else if (crtc->pipe > 0)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100515 return DRM_VBLANK_SECONDARY;
516 else
517 return 0;
518}
519
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200520static int
Jonas Ådahle5a12252013-04-05 23:07:11 +0200521drm_output_start_repaint_loop(struct weston_output *output_base)
522{
Armin Krezović545dba62016-08-05 15:54:18 +0200523 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +0000524 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +0000525 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +0200526 struct drm_backend *backend =
527 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200528 struct timespec ts, tnow;
529 struct timespec vbl2now;
530 int64_t refresh_nsec;
531 int ret;
532 drmVBlank vbl = {
533 .request.type = DRM_VBLANK_RELATIVE,
534 .request.sequence = 0,
535 .request.signal = 0,
536 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300537
Armin Krezović08368132016-09-30 14:11:05 +0200538 if (output->disable_pending || output->destroy_pending)
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200539 return 0;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800540
Daniel Stonee2e80132018-01-16 15:37:33 +0000541 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300542 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200543 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300544 }
545
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300546 /* Need to smash all state in from scratch; current timings might not
547 * be what we want, page flip might not work, etc.
548 */
Daniel Stone6020f472018-02-05 15:46:20 +0000549 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300550 goto finish_frame;
551
Daniel Stonee2e80132018-01-16 15:37:33 +0000552 assert(scanout_plane->state_cur->output == output);
553
Mario Kleinerf507ec32015-06-21 21:25:14 +0200554 /* Try to get current msc and timestamp via instant query */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300555 vbl.request.type |= drm_waitvblank_pipe(output->crtc);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200556 ret = drmWaitVBlank(backend->drm.fd, &vbl);
557
558 /* Error ret or zero timestamp means failure to get valid timestamp */
559 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
560 ts.tv_sec = vbl.reply.tval_sec;
561 ts.tv_nsec = vbl.reply.tval_usec * 1000;
562
563 /* Valid timestamp for most recent vblank - not stale?
564 * Stale ts could happen on Linux 3.17+, so make sure it
565 * is not older than 1 refresh duration since now.
566 */
567 weston_compositor_read_presentation_clock(backend->compositor,
568 &tnow);
569 timespec_sub(&vbl2now, &tnow, &ts);
570 refresh_nsec =
571 millihz_to_nsec(output->base.current_mode->refresh);
572 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
573 drm_output_update_msc(output, vbl.reply.sequence);
574 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200575 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200576 return 0;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200577 }
578 }
579
580 /* Immediate query didn't provide valid timestamp.
581 * Use pageflip fallback.
582 */
Jonas Ådahle5a12252013-04-05 23:07:11 +0200583
Daniel Stone205c0a02017-04-04 17:54:33 +0100584 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000585 assert(!output->state_last);
586
587 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +0000588 drm_output_state_duplicate(output->state_cur, pending_state,
589 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +0100590
Daniel Stone8747f952016-11-29 20:17:32 +0000591 ret = drm_pending_state_apply(pending_state);
592 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200593 weston_log("applying repaint-start state failed: %s\n",
594 strerror(errno));
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200595 if (ret == -EACCES)
596 return -1;
David Herrmann3c688c52013-10-22 17:11:25 +0200597 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200598 }
David Herrmann3c688c52013-10-22 17:11:25 +0200599
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200600 return 0;
David Herrmann3c688c52013-10-22 17:11:25 +0200601
602finish_frame:
603 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +0000604 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200605 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200606 return 0;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200607}
608
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000609/**
610 * Begin a new repaint cycle
611 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000612 * Called by the core compositor at the beginning of a repaint cycle. Creates
613 * a new pending_state structure to own any output state created by individual
614 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000615 */
616static void *
617drm_repaint_begin(struct weston_compositor *compositor)
618{
619 struct drm_backend *b = to_drm_backend(compositor);
620 struct drm_pending_state *ret;
621
622 ret = drm_pending_state_alloc(b);
623 b->repaint_data = ret;
624
Marius Vlad7e4db952019-04-17 13:47:06 +0300625 if (weston_log_scope_is_enabled(b->debug)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100626 char *dbg = weston_compositor_print_scene_graph(compositor);
627 drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
628 ret);
629 drm_debug(b, "%s", dbg);
630 free(dbg);
631 }
632
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000633 return ret;
634}
635
636/**
637 * Flush a repaint set
638 *
639 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000640 * and should be flushed. Frees the pending state, transitioning ownership
641 * of the output state from the pending state, to the update itself. When
642 * the update completes (see drm_output_update_complete), the output
643 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000644 */
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200645static int
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000646drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
647{
648 struct drm_backend *b = to_drm_backend(compositor);
649 struct drm_pending_state *pending_state = repaint_data;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200650 int ret;
Daniel Stone6020f472018-02-05 15:46:20 +0000651
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200652 ret = drm_pending_state_apply(pending_state);
653 if (ret != 0)
654 weston_log("repaint-flush failed: %s\n", strerror(errno));
655
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100656 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000657 b->repaint_data = NULL;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200658
659 return (ret == -EACCES) ? -1 : 0;
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000660}
661
662/**
663 * Cancel a repaint set
664 *
665 * Called by the core compositor when a repaint has finished, so the data
666 * held across the repaint cycle should be discarded.
667 */
668static void
669drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
670{
671 struct drm_backend *b = to_drm_backend(compositor);
672 struct drm_pending_state *pending_state = repaint_data;
673
674 drm_pending_state_free(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100675 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000676 b->repaint_data = NULL;
677}
678
Alex Wub7b8bda2012-04-17 17:20:48 +0800679static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300680drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +0000681static void
682drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200683
684static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800685drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
686{
Daniel Stone02d487a2017-10-07 14:01:45 +0100687 struct drm_output *output = to_drm_output(output_base);
688 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stonefbe6c1d2019-06-17 16:04:26 +0100689 struct drm_mode *drm_mode = drm_output_choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +0800690
691 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +0100692 weston_log("%s: invalid resolution %dx%d\n",
693 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800694 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200695 }
696
Hardeningff39efa2013-09-18 23:56:35 +0200697 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +0800698 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800699
Hardeningff39efa2013-09-18 23:56:35 +0200700 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800701
Hardeningff39efa2013-09-18 23:56:35 +0200702 output->base.current_mode = &drm_mode->base;
703 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800704 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
705
Daniel Stonef30a18c2017-04-04 17:54:31 +0100706 /* XXX: This drops our current buffer too early, before we've started
707 * displaying it. Ideally this should be much more atomic and
708 * integrated with a full repaint cycle, rather than doing a
709 * sledgehammer modeswitch first, and only later showing new
710 * content.
711 */
Daniel Stone6020f472018-02-05 15:46:20 +0000712 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +0800713
Giulio Camuffo954f1832014-10-11 18:27:30 +0300714 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200715 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300716 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200717 weston_log("failed to init output pixman state with "
718 "new mode\n");
719 return -1;
720 }
721 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +0000722 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300723 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200724 weston_log("failed to init output egl state with "
725 "new mode");
726 return -1;
727 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200728 }
729
Alex Wub7b8bda2012-04-17 17:20:48 +0800730 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800731}
732
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200733static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300734init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200735{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300736 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200737}
738
Pekka Paalanen7b36b422014-06-04 14:00:53 +0300739/**
Pekka Paalanenec272712014-06-05 11:22:25 +0300740 * Create a drm_plane for a hardware plane
741 *
742 * Creates one drm_plane structure for a hardware plane, and initialises its
743 * properties and formats.
744 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100745 * In the absence of universal plane support, where KMS does not explicitly
746 * expose the primary and cursor planes to userspace, this may also create
747 * an 'internal' plane for internal management.
748 *
Pekka Paalanenec272712014-06-05 11:22:25 +0300749 * This function does not add the plane to the list of usable planes in Weston
750 * itself; the caller is responsible for this.
751 *
752 * Call drm_plane_destroy to clean up the plane.
753 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100754 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +0300755 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +0100756 * @param kplane DRM plane to create, or NULL if creating internal plane
757 * @param output Output to create internal plane for, or NULL
758 * @param type Type to use when creating internal plane, or invalid
759 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +0300760 */
761static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100762drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
763 struct drm_output *output, enum wdrm_plane_type type,
764 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +0300765{
766 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100767 drmModeObjectProperties *props;
Marius Vladcdd6fa22019-08-29 20:42:00 +0300768 uint64_t *zpos_range_values;
Sergi Granellf4456222017-01-12 17:17:32 +0000769 uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100770
Daniel Stone2ba17f42015-05-19 20:02:41 +0100771 plane = zalloc(sizeof(*plane) +
Sergi Granellf4456222017-01-12 17:17:32 +0000772 (sizeof(plane->formats[0]) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +0300773 if (!plane) {
774 weston_log("%s: out of memory\n", __func__);
775 return NULL;
776 }
777
778 plane->backend = b;
Sergi Granellf4456222017-01-12 17:17:32 +0000779 plane->count_formats = num_formats;
Daniel Stonebc15f682016-11-14 16:57:01 +0000780 plane->state_cur = drm_plane_state_alloc(NULL, plane);
781 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +0300782
Daniel Stone2ba17f42015-05-19 20:02:41 +0100783 if (kplane) {
784 plane->possible_crtcs = kplane->possible_crtcs;
785 plane->plane_id = kplane->plane_id;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100786
787 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
788 DRM_MODE_OBJECT_PLANE);
789 if (!props) {
790 weston_log("couldn't get plane properties\n");
791 goto err;
792 }
793 drm_property_info_populate(b, plane_props, plane->props,
794 WDRM_PLANE__COUNT, props);
795 plane->type =
796 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
797 props,
798 WDRM_PLANE_TYPE__COUNT);
Sergi Granellf4456222017-01-12 17:17:32 +0000799
Marius Vladcdd6fa22019-08-29 20:42:00 +0300800 zpos_range_values =
Daniel Stone7fa97e62020-03-06 11:03:01 +0000801 drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
Marius Vladcdd6fa22019-08-29 20:42:00 +0300802 props);
803
804 if (zpos_range_values) {
805 plane->zpos_min = zpos_range_values[0];
806 plane->zpos_max = zpos_range_values[1];
807 } else {
808 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
809 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
810 }
811
Stefan Agner465ab2c2020-06-17 23:36:44 +0200812 if (drm_plane_populate_formats(plane, kplane, props,
813 b->fb_modifiers) < 0) {
Sergi Granellf4456222017-01-12 17:17:32 +0000814 drmModeFreeObjectProperties(props);
815 goto err;
816 }
817
Daniel Stone2ba17f42015-05-19 20:02:41 +0100818 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100819 }
Daniel Stone2ba17f42015-05-19 20:02:41 +0100820 else {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300821 plane->possible_crtcs = (1 << output->crtc->pipe);
Daniel Stone2ba17f42015-05-19 20:02:41 +0100822 plane->plane_id = 0;
823 plane->count_formats = 1;
Sergi Granellf4456222017-01-12 17:17:32 +0000824 plane->formats[0].format = format;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100825 plane->type = type;
Marius Vladcdd6fa22019-08-29 20:42:00 +0300826 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
827 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100828 }
829
830 if (plane->type == WDRM_PLANE_TYPE__COUNT)
831 goto err_props;
832
833 /* With universal planes, everything is a DRM plane; without
834 * universal planes, the only DRM planes are overlay planes.
835 * Everything else is a fake plane. */
836 if (b->universal_planes) {
837 assert(kplane);
838 } else {
839 if (kplane)
840 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
841 else
842 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
843 output);
844 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100845
Pekka Paalanenec272712014-06-05 11:22:25 +0300846 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +0100847 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +0300848
849 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100850
851err_props:
852 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
853err:
854 drm_plane_state_free(plane->state_cur, true);
855 free(plane);
856 return NULL;
857}
858
859/**
860 * Find, or create, a special-purpose plane
861 *
862 * Primary and cursor planes are a special case, in that before universal
863 * planes, they are driven by non-plane API calls. Without universal plane
864 * support, the only way to configure a primary plane is via drmModeSetCrtc,
865 * and the only way to configure a cursor plane is drmModeSetCursor2.
866 *
867 * Although they may actually be regular planes in the hardware, without
868 * universal plane support, these planes are not actually exposed to
869 * userspace in the regular plane list.
870 *
871 * However, for ease of internal tracking, we want to manage all planes
872 * through the same drm_plane structures. Therefore, when we are running
873 * without universal plane support, we create fake drm_plane structures
874 * to track these planes.
875 *
876 * @param b DRM backend
877 * @param output Output to use for plane
878 * @param type Type of plane
879 */
880static struct drm_plane *
881drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
882 enum wdrm_plane_type type)
883{
884 struct drm_plane *plane;
885
886 if (!b->universal_planes) {
887 uint32_t format;
888
889 switch (type) {
890 case WDRM_PLANE_TYPE_CURSOR:
Stefan Agner0bfebeb2019-07-08 00:30:44 +0200891 format = DRM_FORMAT_ARGB8888;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100892 break;
Daniel Stonee2e80132018-01-16 15:37:33 +0000893 case WDRM_PLANE_TYPE_PRIMARY:
894 /* We don't know what formats the primary plane supports
895 * before universal planes, so we just assume that the
896 * GBM format works; however, this isn't set until after
897 * the output is created. */
898 format = 0;
899 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100900 default:
901 assert(!"invalid type in drm_output_find_special_plane");
902 break;
903 }
904
905 return drm_plane_create(b, NULL, output, type, format);
906 }
907
908 wl_list_for_each(plane, &b->plane_list, link) {
909 struct drm_output *tmp;
910 bool found_elsewhere = false;
911
912 if (plane->type != type)
913 continue;
914 if (!drm_plane_is_available(plane, output))
915 continue;
916
917 /* On some platforms, primary/cursor planes can roam
918 * between different CRTCs, so make sure we don't claim the
919 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +0100920 wl_list_for_each(tmp, &b->compositor->output_list,
921 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +0000922 if (tmp->cursor_plane == plane ||
923 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +0100924 found_elsewhere = true;
925 break;
926 }
927 }
928
929 if (found_elsewhere)
930 continue;
931
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300932 plane->possible_crtcs = (1 << output->crtc->pipe);
Daniel Stone2ba17f42015-05-19 20:02:41 +0100933 return plane;
934 }
935
936 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +0300937}
938
939/**
940 * Destroy one DRM plane
941 *
942 * Destroy a DRM plane, removing it from screen and releasing its retained
943 * buffers in the process. The counterpart to drm_plane_create.
944 *
945 * @param plane Plane to deallocate (will be freed)
946 */
947static void
948drm_plane_destroy(struct drm_plane *plane)
949{
Daniel Stone2ba17f42015-05-19 20:02:41 +0100950 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
951 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
952 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +0000953 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100954 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +0300955 weston_plane_release(&plane->base);
956 wl_list_remove(&plane->link);
957 free(plane);
958}
959
960/**
961 * Initialise sprites (overlay planes)
962 *
963 * Walk the list of provided DRM planes, and add overlay planes.
964 *
965 * Call destroy_sprites to free these planes.
966 *
967 * @param b DRM compositor backend
968 */
969static void
970create_sprites(struct drm_backend *b)
971{
972 drmModePlaneRes *kplane_res;
973 drmModePlane *kplane;
974 struct drm_plane *drm_plane;
975 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +0300976 kplane_res = drmModeGetPlaneResources(b->drm.fd);
977 if (!kplane_res) {
978 weston_log("failed to get plane resources: %s\n",
979 strerror(errno));
980 return;
981 }
982
983 for (i = 0; i < kplane_res->count_planes; i++) {
984 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
985 if (!kplane)
986 continue;
987
Daniel Stone2ba17f42015-05-19 20:02:41 +0100988 drm_plane = drm_plane_create(b, kplane, NULL,
989 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +0300990 drmModeFreePlane(kplane);
991 if (!drm_plane)
992 continue;
993
Daniel Stone085d2b92015-05-21 00:00:57 +0100994 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
995 weston_compositor_stack_plane(b->compositor,
996 &drm_plane->base,
997 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +0300998 }
999
1000 drmModeFreePlaneResources(kplane_res);
1001}
1002
1003/**
1004 * Clean up sprites (overlay planes)
1005 *
1006 * The counterpart to create_sprites.
1007 *
1008 * @param b DRM compositor backend
1009 */
1010static void
1011destroy_sprites(struct drm_backend *b)
1012{
1013 struct drm_plane *plane, *next;
1014
Daniel Stone085d2b92015-05-21 00:00:57 +01001015 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03001016 drm_plane_destroy(plane);
1017}
1018
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001019/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001020static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03001021drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001022{
1023 long brightness, max_brightness, norm;
1024
Pekka Paalanence724242017-09-04 12:21:24 +03001025 brightness = backlight_get_brightness(head->backlight);
1026 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001027
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001028 /* convert it on a scale of 0 to 255 */
1029 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001030
1031 return (uint32_t) norm;
1032}
1033
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001034/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001035static void
1036drm_set_backlight(struct weston_output *output_base, uint32_t value)
1037{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001038 struct drm_output *output = to_drm_output(output_base);
1039 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001040 long max_brightness, new_brightness;
1041
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001042 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001043 return;
1044
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001045 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1046 if (!head->backlight)
1047 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001048
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001049 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001050
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001051 /* get denormalized value */
1052 new_brightness = (value * max_brightness) / 255;
1053
1054 backlight_set_brightness(head->backlight, new_brightness);
1055 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001056}
1057
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001058static void
1059drm_output_init_backlight(struct drm_output *output)
1060{
1061 struct weston_head *base;
1062 struct drm_head *head;
1063
1064 output->base.set_backlight = NULL;
1065
1066 wl_list_for_each(base, &output->base.head_list, output_link) {
1067 head = to_drm_head(base);
1068
1069 if (head->backlight) {
1070 weston_log("Initialized backlight for head '%s', device %s\n",
1071 head->base.name, head->backlight->path);
1072
1073 if (!output->base.set_backlight) {
1074 output->base.set_backlight = drm_set_backlight;
1075 output->base.backlight_current =
1076 drm_get_backlight(head);
1077 }
1078 }
1079 }
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001080}
1081
Daniel Stonea08512f2016-11-08 17:46:10 +00001082/**
1083 * Power output on or off
1084 *
1085 * The DPMS/power level of an output is used to switch it on or off. This
1086 * is DRM's hook for doing so, which can called either as part of repaint,
1087 * or independently of the repaint loop.
1088 *
1089 * If we are called as part of repaint, we simply set the relevant bit in
1090 * state and return.
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001091 *
1092 * This function is never called on a virtual output.
Daniel Stonea08512f2016-11-08 17:46:10 +00001093 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001094static void
1095drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1096{
Armin Krezović545dba62016-08-05 15:54:18 +02001097 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00001098 struct drm_backend *b = to_drm_backend(output_base->compositor);
1099 struct drm_pending_state *pending_state = b->repaint_data;
1100 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01001101 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001102
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001103 assert(!output->virtual);
1104
Daniel Stonea08512f2016-11-08 17:46:10 +00001105 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001106 return;
1107
Daniel Stonea08512f2016-11-08 17:46:10 +00001108 /* If we're being called during the repaint loop, then this is
1109 * simple: discard any previously-generated state, and create a new
1110 * state where we disable everything. When we come to flush, this
1111 * will be applied.
1112 *
1113 * However, we need to be careful: we can be called whilst another
1114 * output is in its repaint cycle (pending_state exists), but our
1115 * output still has an incomplete state application outstanding.
1116 * In that case, we need to wait until that completes. */
1117 if (pending_state && !output->state_last) {
1118 /* The repaint loop already sets DPMS on; we don't need to
1119 * explicitly set it on here, as it will already happen
1120 * whilst applying the repaint state. */
1121 if (level == WESTON_DPMS_ON)
1122 return;
1123
1124 state = drm_pending_state_get_output(pending_state, output);
1125 if (state)
1126 drm_output_state_free(state);
1127 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01001128 return;
1129 }
1130
Daniel Stonea08512f2016-11-08 17:46:10 +00001131 /* As we throw everything away when disabling, just send us back through
1132 * a repaint cycle. */
1133 if (level == WESTON_DPMS_ON) {
1134 if (output->dpms_off_pending)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001135 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +00001136 weston_output_schedule_repaint(output_base);
1137 return;
1138 }
1139
1140 /* If we've already got a request in the pipeline, then we need to
1141 * park our DPMS request until that request has quiesced. */
1142 if (output->state_last) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001143 output->dpms_off_pending = true;
Daniel Stonea08512f2016-11-08 17:46:10 +00001144 return;
1145 }
1146
1147 pending_state = drm_pending_state_alloc(b);
1148 drm_output_get_disable_state(pending_state, output);
1149 ret = drm_pending_state_apply_sync(pending_state);
1150 if (ret != 0)
1151 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001152}
1153
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001154static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001155 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
1156 [DRM_MODE_CONNECTOR_VGA] = "VGA",
1157 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
1158 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
1159 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
1160 [DRM_MODE_CONNECTOR_Composite] = "Composite",
1161 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
1162 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
1163 [DRM_MODE_CONNECTOR_Component] = "Component",
1164 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
1165 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
1166 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
1167 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
1168 [DRM_MODE_CONNECTOR_TV] = "TV",
1169 [DRM_MODE_CONNECTOR_eDP] = "eDP",
1170 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
1171 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Stefan Agner30e283d2018-08-20 17:11:38 +02001172 [DRM_MODE_CONNECTOR_DPI] = "DPI",
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001173};
1174
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001175/** Create a name given a DRM connector
1176 *
1177 * \param con The DRM connector whose type and id form the name.
1178 * \return A newly allocate string, or NULL on error. Must be free()'d
1179 * after use.
1180 *
1181 * The name does not identify the DRM display device.
1182 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001183static char *
1184make_connector_name(const drmModeConnector *con)
1185{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001186 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001187 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001188 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001189
1190 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1191 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001192
1193 if (!type_name)
1194 type_name = "UNNAMED";
1195
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001196 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
1197 if (ret < 0)
1198 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001199
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001200 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001201}
1202
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001203static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001204drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001205{
Hardeningff39efa2013-09-18 23:56:35 +02001206 int w = output->base.current_mode->width;
1207 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001208 uint32_t format = output->gbm_format;
1209 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001210 unsigned int i;
Daniel Stone61abf352020-03-06 12:46:30 +00001211 const struct pixman_renderer_output_options options = {
1212 .use_shadow = b->use_pixman_shadow,
1213 };
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001214
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001215 switch (format) {
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001216 case DRM_FORMAT_XRGB8888:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001217 pixman_format = PIXMAN_x8r8g8b8;
1218 break;
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001219 case DRM_FORMAT_RGB565:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001220 pixman_format = PIXMAN_r5g6b5;
1221 break;
1222 default:
1223 weston_log("Unsupported pixman format 0x%x\n", format);
1224 return -1;
1225 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001226
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001227 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001228 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001229 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001230 if (!output->dumb[i])
1231 goto err;
1232
1233 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001234 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001235 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00001236 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001237 if (!output->image[i])
1238 goto err;
1239 }
1240
Daniel Stone61abf352020-03-06 12:46:30 +00001241 if (pixman_renderer_output_create(&output->base, &options) < 0)
Pekka Paalanendee412d2018-04-23 11:44:58 +02001242 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05301243
Pekka Paalanendee412d2018-04-23 11:44:58 +02001244 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
1245 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001246
1247 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001248 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001249
1250 return 0;
1251
1252err:
1253 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1254 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01001255 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001256 if (output->image[i])
1257 pixman_image_unref(output->image[i]);
1258
1259 output->dumb[i] = NULL;
1260 output->image[i] = NULL;
1261 }
1262
1263 return -1;
1264}
1265
1266static void
1267drm_output_fini_pixman(struct drm_output *output)
1268{
Daniel Stonee2e80132018-01-16 15:37:33 +00001269 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001270 unsigned int i;
1271
Daniel Stonee2e80132018-01-16 15:37:33 +00001272 /* Destroying the Pixman surface will destroy all our buffers,
1273 * regardless of refcount. Ensure we destroy them here. */
1274 if (!b->shutting_down &&
1275 output->scanout_plane->state_cur->fb &&
1276 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
Alexandros Frantzis99751342020-05-18 15:22:49 +03001277 drm_plane_reset_state(output->scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +00001278 }
1279
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001280 pixman_renderer_output_destroy(&output->base);
1281 pixman_region32_fini(&output->previous_damage);
1282
1283 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001284 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001285 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001286 output->dumb[i] = NULL;
1287 output->image[i] = NULL;
1288 }
1289}
1290
Richard Hughes2b2092a2013-04-24 14:58:02 +01001291static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001292setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01001293 struct weston_output *output,
1294 const char *s)
1295{
1296 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05001297 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001298 struct udev_seat *seat;
1299
Giulio Camuffo954f1832014-10-11 18:27:30 +03001300 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05001301 if (!seat)
1302 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001303
Derek Foreman0720ea32015-07-15 13:00:35 -05001304 seat->base.output = output;
1305
Derek Foreman1281a362015-07-31 16:55:32 -05001306 pointer = weston_seat_get_pointer(&seat->base);
1307 if (pointer)
1308 weston_pointer_clamp(pointer,
1309 &pointer->x,
1310 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001311 }
1312}
1313
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001314static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03001315drm_output_attach_head(struct weston_output *output_base,
1316 struct weston_head *head_base)
1317{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001318 struct drm_backend *b = to_drm_backend(output_base->compositor);
1319
Pekka Paalanenc112f002017-08-28 16:27:20 +03001320 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
1321 return -1;
1322
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001323 if (!output_base->enabled)
1324 return 0;
1325
1326 /* XXX: ensure the configuration will work.
1327 * This is actually impossible without major infrastructure
1328 * work. */
1329
1330 /* Need to go through modeset to add connectors. */
1331 /* XXX: Ideally we'd do this per-output, not globally. */
1332 /* XXX: Doing it globally, what guarantees another output's update
1333 * will not clear the flag before this output is updated?
1334 */
1335 b->state_invalid = true;
1336
1337 weston_output_schedule_repaint(output_base);
1338
Pekka Paalanenc112f002017-08-28 16:27:20 +03001339 return 0;
1340}
1341
Pekka Paalanen7f853792017-11-29 14:33:33 +02001342static void
1343drm_output_detach_head(struct weston_output *output_base,
1344 struct weston_head *head_base)
1345{
1346 struct drm_backend *b = to_drm_backend(output_base->compositor);
1347
1348 if (!output_base->enabled)
1349 return;
1350
1351 /* Need to go through modeset to drop connectors that should no longer
1352 * be driven. */
1353 /* XXX: Ideally we'd do this per-output, not globally. */
1354 b->state_invalid = true;
1355
1356 weston_output_schedule_repaint(output_base);
1357}
1358
Stefan Agner3654c672019-07-09 00:50:30 +02001359int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001360parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001361{
Pekka Paalanen62a94362018-09-26 14:33:36 +03001362 const struct pixel_format_info *pinfo;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001363
Pekka Paalanen62a94362018-09-26 14:33:36 +03001364 if (s == NULL) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001365 *gbm_format = default_value;
Pekka Paalanen62a94362018-09-26 14:33:36 +03001366
1367 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001368 }
1369
Pekka Paalanen62a94362018-09-26 14:33:36 +03001370 pinfo = pixel_format_get_info_by_drm_name(s);
1371 if (!pinfo) {
1372 weston_log("fatal: unrecognized pixel format: %s\n", s);
1373
1374 return -1;
1375 }
1376
1377 /* GBM formats and DRM formats are identical. */
1378 *gbm_format = pinfo->format;
1379
1380 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001381}
1382
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001383static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001384drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001385{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001386 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001387 drmModeEncoder *encoder;
1388 drmModeCrtc *crtc;
1389
1390 /* Get the current mode on the crtc that's currently driving
1391 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001392 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001393 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001394 head->inherited_crtc_id = encoder->crtc_id;
1395
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001396 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
1397 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001398
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001399 if (crtc == NULL)
1400 return -1;
1401 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02001402 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001403 drmModeFreeCrtc(crtc);
1404 }
1405
1406 return 0;
1407}
1408
Armin Krezović08368132016-09-30 14:11:05 +02001409static void
1410drm_output_set_gbm_format(struct weston_output *base,
1411 const char *gbm_format)
1412{
1413 struct drm_output *output = to_drm_output(base);
1414 struct drm_backend *b = to_drm_backend(base->compositor);
1415
1416 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
1417 output->gbm_format = b->gbm_format;
1418}
1419
1420static void
1421drm_output_set_seat(struct weston_output *base,
1422 const char *seat)
1423{
1424 struct drm_output *output = to_drm_output(base);
1425 struct drm_backend *b = to_drm_backend(base->compositor);
1426
1427 setup_output_seat_constraint(b, &output->base,
1428 seat ? seat : "");
1429}
1430
1431static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001432drm_output_init_gamma_size(struct drm_output *output)
1433{
1434 struct drm_backend *backend = to_drm_backend(output->base.compositor);
1435 drmModeCrtc *crtc;
1436
1437 assert(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001438 assert(output->crtc);
1439 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc->crtc_id);
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001440 if (!crtc)
1441 return -1;
1442
1443 output->base.gamma_size = crtc->gamma_size;
1444
1445 drmModeFreeCrtc(crtc);
1446
1447 return 0;
1448}
1449
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001450static uint32_t
1451drm_head_get_possible_crtcs_mask(struct drm_head *head)
1452{
1453 uint32_t possible_crtcs = 0;
1454 drmModeEncoder *encoder;
1455 int i;
1456
1457 for (i = 0; i < head->connector->count_encoders; i++) {
1458 encoder = drmModeGetEncoder(head->backend->drm.fd,
1459 head->connector->encoders[i]);
1460 if (!encoder)
1461 continue;
1462
1463 possible_crtcs |= encoder->possible_crtcs;
1464 drmModeFreeEncoder(encoder);
1465 }
1466
1467 return possible_crtcs;
1468}
1469
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001470/** Pick a CRTC that might be able to drive all attached connectors
1471 *
1472 * @param output The output whose attached heads to include.
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001473 * @return CRTC object to pick, or NULL on failure or not found.
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001474 */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001475static struct drm_crtc *
1476drm_output_pick_crtc(struct drm_output *output)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001477{
1478 struct drm_backend *backend;
1479 struct weston_head *base;
1480 struct drm_head *head;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001481 struct drm_crtc *crtc;
1482 struct drm_crtc *best_crtc = NULL;
1483 struct drm_crtc *fallback_crtc = NULL;
1484 struct drm_crtc *existing_crtc[32];
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001485 uint32_t possible_crtcs = 0xffffffff;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001486 unsigned n = 0;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001487 uint32_t crtc_id;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001488 unsigned int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001489 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001490
1491 backend = to_drm_backend(output->base.compositor);
1492
1493 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
1494 * because it is more often set wrong than not in the kernel. */
1495
1496 /* Accumulate a mask of possible crtcs and find existing routings. */
1497 wl_list_for_each(base, &output->base.head_list, output_link) {
1498 head = to_drm_head(base);
1499
1500 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
1501
1502 crtc_id = head->inherited_crtc_id;
1503 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001504 existing_crtc[n++] = drm_crtc_find(backend, crtc_id);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001505 }
1506
1507 /* Find a crtc that could drive each connector individually at least,
1508 * and prefer existing routings. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001509 wl_list_for_each(crtc, &backend->crtc_list, link) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001510
1511 /* Could the crtc not drive each connector? */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001512 if (!(possible_crtcs & (1 << crtc->pipe)))
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001513 continue;
1514
1515 /* Is the crtc already in use? */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001516 if (crtc->output)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001517 continue;
1518
1519 /* Try to preserve the existing CRTC -> connector routing;
1520 * it makes initialisation faster, and also since we have a
1521 * very dumb picking algorithm, may preserve a better
1522 * choice. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001523 for (i = 0; i < n; i++) {
1524 if (existing_crtc[i] == crtc)
1525 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001526 }
1527
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001528 /* Check if any other head had existing routing to this CRTC.
1529 * If they did, this is not the best CRTC as it might be needed
1530 * for another output we haven't enabled yet. */
1531 match = false;
1532 wl_list_for_each(base, &backend->compositor->head_list,
1533 compositor_link) {
1534 head = to_drm_head(base);
1535
1536 if (head->base.output == &output->base)
1537 continue;
1538
1539 if (weston_head_is_enabled(&head->base))
1540 continue;
1541
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001542 if (head->inherited_crtc_id == crtc->crtc_id) {
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001543 match = true;
1544 break;
1545 }
1546 }
1547 if (!match)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001548 best_crtc = crtc;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001549
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001550 fallback_crtc = crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001551 }
1552
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001553 if (best_crtc)
1554 return best_crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001555
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001556 if (fallback_crtc)
1557 return fallback_crtc;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001558
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001559 /* Likely possible_crtcs was empty due to asking for clones,
1560 * but since the DRM documentation says the kernel lies, let's
1561 * pick one crtc anyway. Trial and error is the only way to
1562 * be sure if something doesn't work. */
1563
1564 /* First pick any existing assignment. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001565 for (i = 0; i < n; i++) {
1566 crtc = existing_crtc[i];
1567 if (!crtc->output)
1568 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001569 }
1570
1571 /* Otherwise pick any available crtc. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001572 wl_list_for_each(crtc, &backend->crtc_list, link) {
1573 if (!crtc->output)
1574 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001575 }
1576
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001577 return NULL;
1578}
1579
1580/** Create an "empty" drm_crtc. It will only set its ID, pipe and props. After
1581 * all, it adds the object to the DRM-backend CRTC list.
1582 */
1583static struct drm_crtc *
1584drm_crtc_create(struct drm_backend *b, uint32_t crtc_id, uint32_t pipe)
1585{
1586 struct drm_crtc *crtc;
1587 drmModeObjectPropertiesPtr props;
1588
1589 props = drmModeObjectGetProperties(b->drm.fd, crtc_id,
1590 DRM_MODE_OBJECT_CRTC);
1591 if (!props) {
1592 weston_log("failed to get CRTC properties\n");
1593 return NULL;
1594 }
1595
1596 crtc = zalloc(sizeof(*crtc));
1597 if (!crtc)
1598 goto ret;
1599
1600 drm_property_info_populate(b, crtc_props, crtc->props_crtc,
1601 WDRM_CRTC__COUNT, props);
1602 crtc->backend = b;
1603 crtc->crtc_id = crtc_id;
1604 crtc->pipe = pipe;
1605 crtc->output = NULL;
1606
1607 /* Add it to the last position of the DRM-backend CRTC list */
1608 wl_list_insert(b->crtc_list.prev, &crtc->link);
1609
1610ret:
1611 drmModeFreeObjectProperties(props);
1612 return crtc;
1613}
1614
1615/** Destroy a drm_crtc object that was created with drm_crtc_create(). It will
1616 * also remove it from the DRM-backend CRTC list.
1617 */
1618static void
1619drm_crtc_destroy(struct drm_crtc *crtc)
1620{
1621 /* TODO: address the issue below to be able to remove the comment
1622 * from the assert.
1623 *
1624 * https://gitlab.freedesktop.org/wayland/weston/-/issues/421
1625 */
1626
1627 //assert(!crtc->output);
1628
1629 wl_list_remove(&crtc->link);
1630 drm_property_info_free(crtc->props_crtc, WDRM_CRTC__COUNT);
1631 free(crtc);
1632}
1633
1634/** Find all CRTCs of the fd and create drm_crtc objects for them.
1635 *
1636 * The CRTCs are saved in a list of the drm_backend and will keep there until
1637 * the fd gets closed.
1638 *
1639 * @param b The DRM-backend structure.
1640 * @return 0 on success (at least one CRTC in the list), -1 on failure.
1641 */
1642static int
1643drm_backend_create_crtc_list(struct drm_backend *b)
1644{
1645 drmModeRes *resources;
1646 struct drm_crtc *crtc, *crtc_tmp;
1647 int i;
1648
1649 resources = drmModeGetResources(b->drm.fd);
1650 if (!resources) {
1651 weston_log("drmModeGetResources failed\n");
1652 return -1;
1653 }
1654
1655 /* Iterate through all CRTCs */
1656 for (i = 0; i < resources->count_crtcs; i++) {
1657
1658 /* Let's create an object for the CRTC and add it to the list */
1659 crtc = drm_crtc_create(b, resources->crtcs[i], i);
1660 if (!crtc)
1661 goto err;
1662 }
1663
1664 drmModeFreeResources(resources);
1665 return 0;
1666
1667err:
1668 wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
1669 drm_crtc_destroy(crtc);
1670 drmModeFreeResources(resources);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001671 return -1;
1672}
1673
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001674/** Pick a CRTC and reserve it for the output.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001675 *
1676 * On failure, the output remains without a CRTC.
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001677 *
1678 * @param output The output with no CRTC associated.
1679 * @return 0 on success, -1 on failure.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001680 */
1681static int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001682drm_output_attach_crtc(struct drm_output *output)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001683{
1684 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001685
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001686 output->crtc = drm_output_pick_crtc(output);
1687 if (!output->crtc) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001688 weston_log("Output '%s': No available CRTCs.\n",
1689 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001690 return -1;
1691 }
1692
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001693 output->scanout_plane =
1694 drm_output_find_special_plane(b, output,
1695 WDRM_PLANE_TYPE_PRIMARY);
1696 if (!output->scanout_plane) {
1697 weston_log("Failed to find primary plane for output %s\n",
1698 output->base.name);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001699 output->crtc = NULL;
1700 return -1;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001701 }
1702
Tomohito Esaki51048462020-03-30 17:10:54 +09001703 /* Without universal planes, we can't discover which formats are
1704 * supported by the primary plane; we just hope that the GBM format
1705 * works. */
1706 if (!b->universal_planes)
1707 output->scanout_plane->formats[0].format = output->gbm_format;
1708
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001709 /* Failing to find a cursor plane is not fatal, as we'll fall back
1710 * to software cursor. */
1711 output->cursor_plane =
1712 drm_output_find_special_plane(b, output,
1713 WDRM_PLANE_TYPE_CURSOR);
1714
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001715 /* Reserve the CRTC for the output */
1716 output->crtc->output = output;
1717 wl_array_remove_uint32(&b->unused_crtcs, output->crtc->crtc_id);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001718
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001719 return 0;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001720}
1721
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001722/** Release reservation of the CRTC.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001723 *
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001724 * Make the CRTC free to be reserved and used by another output.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001725 *
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001726 * @param output The output that will release its CRTC.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001727 */
1728static void
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001729drm_output_detach_crtc(struct drm_output *output)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001730{
1731 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001732 struct drm_crtc *crtc = output->crtc;
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001733 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001734
Alexandros Frantzis53a71cb2020-05-18 15:26:01 +03001735 /* If the compositor is already shutting down, the planes have already
1736 * been destroyed. */
1737 if (!b->shutting_down) {
1738 if (!b->universal_planes) {
1739 /* Without universal planes, our special planes are
1740 * pseudo-planes allocated at output creation, freed at
1741 * output destruction, and not usable by other outputs.
1742 */
1743 if (output->cursor_plane)
1744 drm_plane_destroy(output->cursor_plane);
1745 if (output->scanout_plane)
1746 drm_plane_destroy(output->scanout_plane);
1747 } else {
1748 /* With universal planes, the 'special' planes are
1749 * allocated at startup, freed at shutdown, and live on
1750 * the plane list in between. We want the planes to
1751 * continue to exist and be freed up for other outputs.
1752 */
1753 if (output->cursor_plane)
1754 drm_plane_reset_state(output->cursor_plane);
1755 if (output->scanout_plane)
1756 drm_plane_reset_state(output->scanout_plane);
1757 }
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001758 }
1759
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001760 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001761 *unused = crtc->crtc_id;
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001762
1763 /* Force resetting unused CRTCs */
1764 b->state_invalid = true;
1765
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001766 crtc->output = NULL;
1767 output->crtc = NULL;
1768
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001769 output->cursor_plane = NULL;
1770 output->scanout_plane = NULL;
1771}
1772
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001773static int
Armin Krezović08368132016-09-30 14:11:05 +02001774drm_output_enable(struct weston_output *base)
1775{
1776 struct drm_output *output = to_drm_output(base);
1777 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001778 int ret;
1779
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001780 assert(!output->virtual);
1781
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001782 ret = drm_output_attach_crtc(output);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001783 if (ret < 0)
1784 return -1;
1785
1786 if (drm_output_init_gamma_size(output) < 0)
1787 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02001788
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001789 if (b->pageflip_timeout)
1790 drm_output_pageflip_timer_create(output);
1791
Giulio Camuffo954f1832014-10-11 18:27:30 +03001792 if (b->use_pixman) {
1793 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001794 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00001795 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001796 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03001797 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001798 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00001799 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001800 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001801
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001802 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001803
Jonas Ådahle5a12252013-04-05 23:07:11 +02001804 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001805 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001806 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001807 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001808 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01001809 output->base.set_gamma = drm_output_set_gamma;
1810
Daniel Stone2ba17f42015-05-19 20:02:41 +01001811 if (output->cursor_plane)
1812 weston_compositor_stack_plane(b->compositor,
1813 &output->cursor_plane->base,
1814 NULL);
1815 else
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001816 b->cursors_are_broken = true;
Daniel Stone2ba17f42015-05-19 20:02:41 +01001817
Daniel Stonee2e80132018-01-16 15:37:33 +00001818 weston_compositor_stack_plane(b->compositor,
1819 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001820 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001821
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001822 weston_log("Output %s (crtc %d) video modes:\n",
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001823 output->base.name, output->crtc->crtc_id);
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001824 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001825
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001826 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001827
Daniel Stone02cf4662017-03-03 16:19:39 +00001828err:
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001829 drm_output_detach_crtc(output);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001830 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001831}
1832
Jesse Barnes58ef3792012-02-23 09:45:49 -05001833static void
Armin Krezović08368132016-09-30 14:11:05 +02001834drm_output_deinit(struct weston_output *base)
1835{
1836 struct drm_output *output = to_drm_output(base);
1837 struct drm_backend *b = to_drm_backend(base->compositor);
1838
Daniel Stone3e661f72016-11-04 17:24:06 +00001839 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02001840 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00001841 else
1842 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02001843
Daniel Stone2ba17f42015-05-19 20:02:41 +01001844 /* Since our planes are no longer in use anywhere, remove their base
1845 * weston_plane's link from the plane stacking list, unless we're
1846 * shutting down, in which case the plane has already been
1847 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00001848 if (!b->shutting_down) {
1849 wl_list_remove(&output->scanout_plane->base.link);
1850 wl_list_init(&output->scanout_plane->base.link);
1851
1852 if (output->cursor_plane) {
1853 wl_list_remove(&output->cursor_plane->base.link);
1854 wl_list_init(&output->cursor_plane->base.link);
1855 /* Turn off hardware cursor */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001856 drmModeSetCursor(b->drm.fd, output->crtc->crtc_id, 0, 0, 0);
Daniel Stonee2e80132018-01-16 15:37:33 +00001857 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01001858 }
Daniel Stone087ddf02017-02-14 17:51:30 +00001859
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001860 drm_output_detach_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02001861}
1862
1863static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03001864drm_head_destroy(struct drm_head *head);
1865
1866static void
Armin Krezović08368132016-09-30 14:11:05 +02001867drm_output_destroy(struct weston_output *base)
1868{
1869 struct drm_output *output = to_drm_output(base);
1870 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02001871
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001872 assert(!output->virtual);
1873
Daniel Stone31838bf2019-06-17 11:23:25 +01001874 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001875 output->destroy_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001876 weston_log("destroy output while page flip pending\n");
1877 return;
1878 }
1879
1880 if (output->base.enabled)
1881 drm_output_deinit(&output->base);
1882
Pekka Paalanen383b3af2017-09-11 14:40:48 +03001883 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02001884
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001885 if (output->pageflip_timer)
1886 wl_event_source_remove(output->pageflip_timer);
1887
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03001888 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02001889
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001890 assert(!output->state_last);
1891 drm_output_state_free(output->state_cur);
1892
Armin Krezović08368132016-09-30 14:11:05 +02001893 free(output);
1894}
1895
1896static int
1897drm_output_disable(struct weston_output *base)
1898{
1899 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02001900
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001901 assert(!output->virtual);
1902
Daniel Stone31838bf2019-06-17 11:23:25 +01001903 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001904 output->disable_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001905 return -1;
1906 }
1907
Daniel Stonea08512f2016-11-08 17:46:10 +00001908 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00001909
Armin Krezović08368132016-09-30 14:11:05 +02001910 if (output->base.enabled)
1911 drm_output_deinit(&output->base);
1912
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001913 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02001914
Armin Krezović08368132016-09-30 14:11:05 +02001915 return 0;
1916}
1917
1918/**
Daniel Stone087ddf02017-02-14 17:51:30 +00001919 * Update the list of unused connectors and CRTCs
1920 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03001921 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00001922 *
1923 * @param b Weston backend structure
1924 * @param resources DRM resources for this device
1925 */
1926static void
1927drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
1928{
1929 int i;
1930
Daniel Stone087ddf02017-02-14 17:51:30 +00001931 wl_array_release(&b->unused_crtcs);
1932 wl_array_init(&b->unused_crtcs);
1933
1934 for (i = 0; i < resources->count_crtcs; i++) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001935 struct drm_output *output = NULL;
1936 struct drm_crtc *crtc;
Daniel Stone087ddf02017-02-14 17:51:30 +00001937 uint32_t *crtc_id;
1938
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001939 crtc = drm_crtc_find(b, resources->crtcs[i]);
1940 if (crtc)
1941 output = crtc->output;
1942
Daniel Stone087ddf02017-02-14 17:51:30 +00001943 if (output && output->base.enabled)
1944 continue;
1945
1946 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
1947 *crtc_id = resources->crtcs[i];
1948 }
1949}
1950
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301951/*
1952 * This function converts the protection status from drm values to
1953 * weston_hdcp_protection status. The drm values as read from the connector
1954 * properties "Content Protection" and "HDCP Content Type" need to be converted
1955 * to appropriate weston values, that can be sent to a client application.
1956 */
1957static int
1958get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
1959 enum wdrm_hdcp_content_type type,
1960 enum weston_hdcp_protection *weston_protection)
1961
1962{
1963 if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
1964 return -1;
1965 if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
1966 protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
1967 *weston_protection = WESTON_HDCP_DISABLE;
1968 return 0;
1969 }
1970 if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
1971 return -1;
1972 if (type == WDRM_HDCP_CONTENT_TYPE0) {
1973 *weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
1974 return 0;
1975 }
1976 if (type == WDRM_HDCP_CONTENT_TYPE1) {
1977 *weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
1978 return 0;
1979 }
1980 return -1;
1981}
1982
1983/**
1984 * Get current content-protection status for a given head.
1985 *
1986 * @param head drm_head, whose protection is to be retrieved
1987 * @param props drm property object of the connector, related to the head
1988 * @return protection status in case of success, -1 otherwise
1989 */
1990static enum weston_hdcp_protection
1991drm_head_get_current_protection(struct drm_head *head,
1992 drmModeObjectProperties *props)
1993{
1994 struct drm_property_info *info;
1995 enum wdrm_content_protection_state protection;
1996 enum wdrm_hdcp_content_type type;
1997 enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
1998
1999 info = &head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION];
2000 protection = drm_property_get_value(info, props,
2001 WDRM_CONTENT_PROTECTION__COUNT);
2002
2003 if (protection == WDRM_CONTENT_PROTECTION__COUNT)
2004 return WESTON_HDCP_DISABLE;
2005
2006 info = &head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
2007 type = drm_property_get_value(info, props,
2008 WDRM_HDCP_CONTENT_TYPE__COUNT);
2009
2010 /*
2011 * In case of platforms supporting HDCP1.4, only property
2012 * 'Content Protection' is exposed and not the 'HDCP Content Type'
2013 * for such cases HDCP Type 0 should be considered as the content-type.
2014 */
2015
2016 if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
2017 type = WDRM_HDCP_CONTENT_TYPE0;
2018
2019 if (get_weston_protection_from_drm(protection, type,
2020 &weston_hdcp) == -1) {
2021 weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
2022 protection, type, head->base.name,
2023 head->connector_id);
2024 return WESTON_HDCP_DISABLE;
2025 }
2026
2027 return weston_hdcp;
2028}
2029
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002030/** Replace connector data and monitor information
2031 *
2032 * @param head The head to update.
2033 * @param connector The connector data to be owned by the head, must match
2034 * the head's connector ID.
2035 * @return 0 on success, -1 on failure.
2036 *
2037 * Takes ownership of @c connector on success, not on failure.
2038 *
2039 * May schedule a heads changed call.
2040 */
2041static int
2042drm_head_assign_connector_info(struct drm_head *head,
2043 drmModeConnector *connector)
2044{
2045 drmModeObjectProperties *props;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002046
2047 assert(connector);
2048 assert(head->connector_id == connector->connector_id);
2049
2050 props = drmModeObjectGetProperties(head->backend->drm.fd,
2051 head->connector_id,
2052 DRM_MODE_OBJECT_CONNECTOR);
2053 if (!props) {
2054 weston_log("Error: failed to get connector '%s' properties\n",
2055 head->base.name);
2056 return -1;
2057 }
2058
2059 if (head->connector)
2060 drmModeFreeConnector(head->connector);
2061 head->connector = connector;
2062
2063 drm_property_info_populate(head->backend, connector_props,
2064 head->props_conn,
2065 WDRM_CONNECTOR__COUNT, props);
Daniel Stone3448cfc2019-06-26 22:56:39 +01002066 update_head_from_connector(head, props);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302067
2068 weston_head_set_content_protection_status(&head->base,
2069 drm_head_get_current_protection(head, props));
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002070 drmModeFreeObjectProperties(props);
2071
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002072 return 0;
2073}
2074
Pekka Paalanen456dc732017-11-09 15:10:11 +02002075static void
2076drm_head_log_info(struct drm_head *head, const char *msg)
2077{
2078 if (head->base.connected) {
2079 weston_log("DRM: head '%s' %s, connector %d is connected, "
2080 "EDID make '%s', model '%s', serial '%s'\n",
2081 head->base.name, msg, head->connector_id,
2082 head->base.make, head->base.model,
2083 head->base.serial_number ?: "");
2084 } else {
2085 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
2086 head->base.name, msg, head->connector_id);
2087 }
2088}
2089
Pekka Paalanend2e62422017-09-08 15:48:07 +03002090/** Update connector and monitor information
2091 *
2092 * @param head The head to update.
2093 *
2094 * Re-reads the DRM property lists for the connector and updates monitor
2095 * information and connection status. This may schedule a heads changed call
2096 * to the user.
2097 */
2098static void
2099drm_head_update_info(struct drm_head *head)
2100{
2101 drmModeConnector *connector;
2102
2103 connector = drmModeGetConnector(head->backend->drm.fd,
2104 head->connector_id);
2105 if (!connector) {
2106 weston_log("DRM: getting connector info for '%s' failed.\n",
2107 head->base.name);
2108 return;
2109 }
2110
2111 if (drm_head_assign_connector_info(head, connector) < 0)
2112 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002113
2114 if (head->base.device_changed)
2115 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03002116}
2117
Daniel Stone087ddf02017-02-14 17:51:30 +00002118/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03002119 * Create a Weston head for a connector
2120 *
2121 * Given a DRM connector, create a matching drm_head structure and add it
2122 * to Weston's head list.
2123 *
Marius Vlada2dace22019-06-12 16:05:44 +03002124 * @param backend Weston backend structure
Pekka Paalanenc112f002017-08-28 16:27:20 +03002125 * @param connector_id DRM connector ID for the head
2126 * @param drm_device udev device pointer
2127 * @returns The new head, or NULL on failure.
2128 */
2129static struct drm_head *
2130drm_head_create(struct drm_backend *backend, uint32_t connector_id,
2131 struct udev_device *drm_device)
2132{
2133 struct drm_head *head;
2134 drmModeConnector *connector;
2135 char *name;
2136
2137 head = zalloc(sizeof *head);
2138 if (!head)
2139 return NULL;
2140
2141 connector = drmModeGetConnector(backend->drm.fd, connector_id);
2142 if (!connector)
2143 goto err_alloc;
2144
2145 name = make_connector_name(connector);
2146 if (!name)
2147 goto err_alloc;
2148
2149 weston_head_init(&head->base, name);
2150 free(name);
2151
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002152 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002153 head->backend = backend;
2154
Pekka Paalanence724242017-09-04 12:21:24 +03002155 head->backlight = backlight_init(drm_device, connector->connector_type);
2156
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002157 if (drm_head_assign_connector_info(head, connector) < 0)
2158 goto err_init;
2159
2160 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
2161 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
2162 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002163
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02002164 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002165 weston_log("Failed to retrieve current mode from connector %d.\n",
2166 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02002167 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002168 }
2169
Pekka Paalanenc112f002017-08-28 16:27:20 +03002170 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002171 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03002172
2173 return head;
2174
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002175err_init:
2176 weston_head_release(&head->base);
2177
Pekka Paalanenc112f002017-08-28 16:27:20 +03002178err_alloc:
2179 if (connector)
2180 drmModeFreeConnector(connector);
2181
2182 free(head);
2183
2184 return NULL;
2185}
2186
2187static void
2188drm_head_destroy(struct drm_head *head)
2189{
2190 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03002191
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002192 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
2193 drmModeFreeConnector(head->connector);
2194
Pekka Paalanence724242017-09-04 12:21:24 +03002195 if (head->backlight)
2196 backlight_destroy(head->backlight);
2197
Pekka Paalanenc112f002017-08-28 16:27:20 +03002198 free(head);
2199}
2200
2201/**
Armin Krezović08368132016-09-30 14:11:05 +02002202 * Create a Weston output structure
2203 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002204 * Create an "empty" drm_output. This is the implementation of
2205 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02002206 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002207 * Creating an output is usually followed by drm_output_attach_head()
2208 * and drm_output_enable() to make use of it.
2209 *
2210 * @param compositor The compositor instance.
2211 * @param name Name for the new output.
2212 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02002213 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03002214static struct weston_output *
2215drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02002216{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002217 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02002218 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02002219
Armin Krezović08368132016-09-30 14:11:05 +02002220 output = zalloc(sizeof *output);
2221 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002222 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02002223
Daniel Stone64dbbee2018-07-20 19:00:06 +01002224 output->backend = b;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002225 output->crtc = NULL;
2226
Stefan Agnerccf24072019-07-09 22:02:00 +02002227#ifdef BUILD_DRM_GBM
Tomohito Esaki718a40b2018-01-31 17:50:15 +09002228 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Stefan Agnerccf24072019-07-09 22:02:00 +02002229#endif
Daniel Stone64dbbee2018-07-20 19:00:06 +01002230
Pekka Paalanend2e62422017-09-08 15:48:07 +03002231 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002232
Armin Krezović08368132016-09-30 14:11:05 +02002233 output->base.enable = drm_output_enable;
2234 output->base.destroy = drm_output_destroy;
2235 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002236 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02002237 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02002238
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002239 output->destroy_pending = false;
2240 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02002241
Pekka Paalanen01f60212017-03-24 15:39:24 +02002242 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03002243
Armin Krezović08368132016-09-30 14:11:05 +02002244 weston_compositor_add_pending_output(&output->base, b->compositor);
2245
Pekka Paalanend2e62422017-09-08 15:48:07 +03002246 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02002247}
2248
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002249static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03002250drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002251{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002252 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002253 drmModeRes *resources;
2254 int i;
2255
Giulio Camuffo954f1832014-10-11 18:27:30 +03002256 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002257 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002258 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002259 return -1;
2260 }
2261
Giulio Camuffo954f1832014-10-11 18:27:30 +03002262 b->min_width = resources->min_width;
2263 b->max_width = resources->max_width;
2264 b->min_height = resources->min_height;
2265 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002266
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002267 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002268 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00002269
Pekka Paalanend2e62422017-09-08 15:48:07 +03002270 head = drm_head_create(b, connector_id, drm_device);
2271 if (!head) {
2272 weston_log("DRM: failed to create head for connector %d.\n",
2273 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002274 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002275 }
2276
Daniel Stone087ddf02017-02-14 17:51:30 +00002277 drm_backend_update_unused_outputs(b, resources);
2278
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002279 drmModeFreeResources(resources);
2280
2281 return 0;
2282}
2283
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002284static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03002285drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002286{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002287 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002288 struct weston_head *base, *next;
2289 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002290 int i;
2291
Giulio Camuffo954f1832014-10-11 18:27:30 +03002292 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002293 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002294 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002295 return;
2296 }
2297
Pekka Paalanend2e62422017-09-08 15:48:07 +03002298 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002299 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00002300 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02002301
Pekka Paalanend2e62422017-09-08 15:48:07 +03002302 head = drm_head_find_by_connector(b, connector_id);
2303 if (head) {
2304 drm_head_update_info(head);
2305 } else {
2306 head = drm_head_create(b, connector_id, drm_device);
2307 if (!head)
2308 weston_log("DRM: failed to create head for hot-added connector %d.\n",
2309 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002310 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002311 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002312
Pekka Paalanend2e62422017-09-08 15:48:07 +03002313 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03002314 wl_list_for_each_safe(base, next,
2315 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002316 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002317
Pekka Paalanena0a37462017-08-31 15:41:57 +03002318 head = to_drm_head(base);
2319
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002320 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002321 if (resources->connectors[i] == head->connector_id) {
2322 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002323 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002324 }
2325 }
Armin Krezović08368132016-09-30 14:11:05 +02002326
Pekka Paalanend2e62422017-09-08 15:48:07 +03002327 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002328 continue;
2329
Pekka Paalanend2e62422017-09-08 15:48:07 +03002330 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
2331 head->base.name, head->connector_id);
2332 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002333 }
2334
Daniel Stone087ddf02017-02-14 17:51:30 +00002335 drm_backend_update_unused_outputs(b, resources);
2336
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002337 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002338}
2339
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302340static enum wdrm_connector_property
2341drm_head_find_property_by_id(struct drm_head *head, uint32_t property_id)
2342{
2343 int i;
2344 enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
2345
2346 if (!head || !property_id)
2347 return WDRM_CONNECTOR__COUNT;
2348
2349 for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
2350 if (head->props_conn[i].prop_id == property_id) {
2351 prop = (enum wdrm_connector_property) i;
2352 break;
2353 }
2354 return prop;
2355}
2356
2357static void
2358drm_backend_update_conn_props(struct drm_backend *b,
2359 uint32_t connector_id,
2360 uint32_t property_id)
2361{
2362 struct drm_head *head;
2363 enum wdrm_connector_property conn_prop;
2364 drmModeObjectProperties *props;
2365
2366 head = drm_head_find_by_connector(b, connector_id);
2367 if (!head) {
2368 weston_log("DRM: failed to find head for connector id: %d.\n",
2369 connector_id);
2370 return;
2371 }
2372
2373 conn_prop = drm_head_find_property_by_id(head, property_id);
2374 if (conn_prop >= WDRM_CONNECTOR__COUNT)
2375 return;
2376
2377 props = drmModeObjectGetProperties(b->drm.fd,
2378 connector_id,
2379 DRM_MODE_OBJECT_CONNECTOR);
2380 if (!props) {
2381 weston_log("Error: failed to get connector '%s' properties\n",
2382 head->base.name);
2383 return;
2384 }
2385 if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
2386 weston_head_set_content_protection_status(&head->base,
2387 drm_head_get_current_protection(head, props));
2388 }
2389 drmModeFreeObjectProperties(props);
2390}
2391
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002392static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002393udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002394{
David Herrmannd7488c22012-03-11 20:05:21 +01002395 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002396 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002397
2398 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002399 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002400 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002401
David Herrmann6ac52db2012-03-11 20:05:22 +01002402 val = udev_device_get_property_value(device, "HOTPLUG");
2403 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002404 return 0;
2405
David Herrmann6ac52db2012-03-11 20:05:22 +01002406 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002407}
2408
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002409static int
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302410udev_event_is_conn_prop_change(struct drm_backend *b,
2411 struct udev_device *device,
2412 uint32_t *connector_id,
2413 uint32_t *property_id)
2414
2415{
2416 const char *val;
2417 int id;
2418
2419 val = udev_device_get_property_value(device, "CONNECTOR");
2420 if (!val || !safe_strtoint(val, &id))
2421 return 0;
2422 else
2423 *connector_id = id;
2424
2425 val = udev_device_get_property_value(device, "PROPERTY");
2426 if (!val || !safe_strtoint(val, &id))
2427 return 0;
2428 else
2429 *property_id = id;
2430
2431 return 1;
2432}
2433
2434static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002435udev_drm_event(int fd, uint32_t mask, void *data)
2436{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002437 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002438 struct udev_device *event;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302439 uint32_t conn_id, prop_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002440
Giulio Camuffo954f1832014-10-11 18:27:30 +03002441 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002442
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302443 if (udev_event_is_hotplug(b, event)) {
2444 if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
2445 drm_backend_update_conn_props(b, conn_id, prop_id);
2446 else
2447 drm_backend_update_heads(b, event);
2448 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002449
2450 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002451
2452 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002453}
2454
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002455static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002456drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002457{
Armin Krezović545dba62016-08-05 15:54:18 +02002458 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002459 struct weston_head *base, *next;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002460 struct drm_crtc *crtc, *crtc_tmp;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002461
Giulio Camuffo954f1832014-10-11 18:27:30 +03002462 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002463
Giulio Camuffo954f1832014-10-11 18:27:30 +03002464 wl_event_source_remove(b->udev_drm_source);
2465 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002466
Daniel Stoneb57c6a02017-10-05 16:27:21 +01002467 b->shutting_down = true;
2468
Giulio Camuffo954f1832014-10-11 18:27:30 +03002469 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002470
Leandro Ribeirof0149642019-12-18 15:52:18 -03002471 weston_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002472 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002473 weston_compositor_shutdown(ec);
2474
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002475 wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
2476 drm_crtc_destroy(crtc);
2477
Pekka Paalanenc112f002017-08-28 16:27:20 +03002478 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
2479 drm_head_destroy(to_drm_head(base));
2480
Stefan Agnerccf24072019-07-09 22:02:00 +02002481#ifdef BUILD_DRM_GBM
Giulio Camuffo954f1832014-10-11 18:27:30 +03002482 if (b->gbm)
2483 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02002484#endif
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002485
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02002486 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03002487 udev_unref(b->udev);
2488
Giulio Camuffo954f1832014-10-11 18:27:30 +03002489 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002490
Daniel Stone087ddf02017-02-14 17:51:30 +00002491 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00002492
Giulio Camuffo954f1832014-10-11 18:27:30 +03002493 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02002494 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002495 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002496}
2497
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002498static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002499session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002500{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002501 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02002502 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01002503 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002504 struct drm_output *output;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002505 struct drm_crtc *crtc;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002506
Giulio Camuffo954f1832014-10-11 18:27:30 +03002507 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002508 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00002509 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002510 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00002511 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002512 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002513 } else {
2514 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002515 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002516
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002517 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002518
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002519 /* If we have a repaint scheduled (either from a
2520 * pending pageflip or the idle handler), make sure we
2521 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002522 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002523 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002524 * back, we schedule a repaint, which will process
2525 * pending frame callbacks. */
2526
Giulio Camuffo954f1832014-10-11 18:27:30 +03002527 wl_list_for_each(output, &compositor->output_list, base.link) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002528 crtc = output->crtc;
Daniel Stone09a97e22017-03-01 11:34:06 +00002529 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002530 if (output->cursor_plane)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002531 drmModeSetCursor(b->drm.fd, crtc->crtc_id,
Daniel Stone2ba17f42015-05-19 20:02:41 +01002532 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002533 }
2534
Giulio Camuffo954f1832014-10-11 18:27:30 +03002535 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002536 struct drm_output, base.link);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002537 crtc = output->crtc;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002538
Daniel Stone085d2b92015-05-21 00:00:57 +01002539 wl_list_for_each(plane, &b->plane_list, link) {
2540 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
2541 continue;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002542 drmModeSetPlane(b->drm.fd, plane->plane_id, crtc->crtc_id,
2543 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01002544 }
2545 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002546}
2547
Robert Beckett8d23ab72019-06-13 16:55:44 +01002548
2549/**
2550 * Handle KMS GPU being added/removed
2551 *
2552 * If the device being added/removed is the KMS device, we activate/deactivate
2553 * the compositor session.
2554 *
2555 * @param compositor The compositor instance.
2556 * @param device The device being added/removed.
2557 * @param added Whether the device is being added (or removed)
2558 */
2559static void
2560drm_device_changed(struct weston_compositor *compositor,
2561 dev_t device, bool added)
2562{
2563 struct drm_backend *b = to_drm_backend(compositor);
2564
Robert Beckett49dc3202019-07-02 16:31:22 +01002565 if (b->drm.fd < 0 || b->drm.devnum != device ||
2566 compositor->session_active == added)
Robert Beckett8d23ab72019-06-13 16:55:44 +01002567 return;
2568
2569 compositor->session_active = added;
2570 wl_signal_emit(&compositor->session_signal, compositor);
2571}
2572
Daniel Stoneefa504f2016-12-19 16:48:20 +00002573/**
2574 * Determines whether or not a device is capable of modesetting. If successful,
2575 * sets b->drm.fd and b->drm.filename to the opened device.
2576 */
2577static bool
2578drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2579{
2580 const char *filename = udev_device_get_devnode(device);
2581 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002582 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002583 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02002584 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002585
2586 if (!filename)
2587 return false;
2588
2589 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
2590 if (fd < 0)
2591 return false;
2592
2593 res = drmModeGetResources(fd);
2594 if (!res)
2595 goto out_fd;
2596
2597 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2598 res->count_encoders <= 0)
2599 goto out_res;
2600
2601 if (sysnum)
2602 id = atoi(sysnum);
2603 if (!sysnum || id < 0) {
2604 weston_log("couldn't get sysnum for device %s\n", filename);
2605 goto out_res;
2606 }
2607
2608 /* We can be called successfully on multiple devices; if we have,
2609 * clean up old entries. */
2610 if (b->drm.fd >= 0)
2611 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2612 free(b->drm.filename);
2613
2614 b->drm.fd = fd;
2615 b->drm.id = id;
2616 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002617 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002618
Sergi Granellceb59812017-03-28 12:44:04 +02002619 drmModeFreeResources(res);
2620
Daniel Stoneefa504f2016-12-19 16:48:20 +00002621 return true;
2622
2623out_res:
2624 drmModeFreeResources(res);
2625out_fd:
2626 weston_launcher_close(b->compositor->launcher, fd);
2627 return false;
2628}
2629
David Herrmann0af066f2012-10-29 19:21:16 +01002630/*
2631 * Find primary GPU
2632 * Some systems may have multiple DRM devices attached to a single seat. This
2633 * function loops over all devices and tries to find a PCI device with the
2634 * boot_vga sysfs attribute set to 1.
2635 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00002636 * Devices are also vetted to make sure they are are capable of modesetting,
2637 * rather than pure render nodes (GPU with no display), or pure
2638 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01002639 */
2640static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002641find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002642{
2643 struct udev_enumerate *e;
2644 struct udev_list_entry *entry;
2645 const char *path, *device_seat, *id;
2646 struct udev_device *device, *drm_device, *pci;
2647
Giulio Camuffo954f1832014-10-11 18:27:30 +03002648 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002649 udev_enumerate_add_match_subsystem(e, "drm");
2650 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2651
2652 udev_enumerate_scan_devices(e);
2653 drm_device = NULL;
2654 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00002655 bool is_boot_vga = false;
2656
David Herrmann0af066f2012-10-29 19:21:16 +01002657 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002658 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002659 if (!device)
2660 continue;
2661 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2662 if (!device_seat)
2663 device_seat = default_seat;
2664 if (strcmp(device_seat, seat)) {
2665 udev_device_unref(device);
2666 continue;
2667 }
2668
2669 pci = udev_device_get_parent_with_subsystem_devtype(device,
2670 "pci", NULL);
2671 if (pci) {
2672 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00002673 if (id && !strcmp(id, "1"))
2674 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01002675 }
2676
Daniel Stoneefa504f2016-12-19 16:48:20 +00002677 /* If we already have a modesetting-capable device, and this
2678 * device isn't our boot-VGA device, we aren't going to use
2679 * it. */
2680 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01002681 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002682 continue;
2683 }
2684
2685 /* Make sure this device is actually capable of modesetting;
2686 * if this call succeeds, b->drm.{fd,filename} will be set,
2687 * and any old values freed. */
2688 if (!drm_device_is_kms(b, device)) {
2689 udev_device_unref(device);
2690 continue;
2691 }
2692
2693 /* There can only be one boot_vga device, and we try to use it
2694 * at all costs. */
2695 if (is_boot_vga) {
2696 if (drm_device)
2697 udev_device_unref(drm_device);
2698 drm_device = device;
2699 break;
2700 }
2701
2702 /* Per the (!is_boot_vga && drm_device) test above, we only
2703 * trump existing saved devices with boot-VGA devices, so if
2704 * we end up here, this must be the first device we've seen. */
2705 assert(!drm_device);
2706 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01002707 }
2708
Daniel Stoneefa504f2016-12-19 16:48:20 +00002709 /* If we're returning a device to use, we must have an open FD for
2710 * it. */
2711 assert(!!drm_device == (b->drm.fd >= 0));
2712
David Herrmann0af066f2012-10-29 19:21:16 +01002713 udev_enumerate_unref(e);
2714 return drm_device;
2715}
2716
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002717static struct udev_device *
2718open_specific_drm_device(struct drm_backend *b, const char *name)
2719{
2720 struct udev_device *device;
2721
2722 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2723 if (!device) {
2724 weston_log("ERROR: could not open DRM device '%s'\n", name);
2725 return NULL;
2726 }
2727
2728 if (!drm_device_is_kms(b, device)) {
2729 udev_device_unref(device);
2730 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2731 return NULL;
2732 }
2733
2734 /* If we're returning a device to use, we must have an open FD for
2735 * it. */
2736 assert(b->drm.fd >= 0);
2737
2738 return device;
2739}
2740
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002741static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002742planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2743 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002744{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002745 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002746
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002747 switch (key) {
2748 case KEY_C:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002749 b->cursors_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002750 break;
2751 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01002752 /* We don't support overlay-plane usage with legacy KMS. */
2753 if (b->atomic_modeset)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002754 b->sprites_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002755 break;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002756 default:
2757 break;
2758 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002759}
2760
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002761#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002762static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002763recorder_destroy(struct drm_output *output)
2764{
2765 vaapi_recorder_destroy(output->recorder);
2766 output->recorder = NULL;
2767
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302768 weston_output_disable_planes_decr(&output->base);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002769
2770 wl_list_remove(&output->recorder_frame_listener.link);
2771 weston_log("[libva recorder] done\n");
2772}
2773
2774static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002775recorder_frame_notify(struct wl_listener *listener, void *data)
2776{
2777 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002778 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002779 int fd, ret;
2780
2781 output = container_of(listener, struct drm_output,
2782 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02002783 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002784
2785 if (!output->recorder)
2786 return;
2787
Daniel Stonee2e80132018-01-16 15:37:33 +00002788 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002789 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002790 DRM_CLOEXEC, &fd);
2791 if (ret) {
2792 weston_log("[libva recorder] "
2793 "failed to create prime fd for front buffer\n");
2794 return;
2795 }
2796
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002797 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002798 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002799 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002800 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002801 recorder_destroy(output);
2802 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002803}
2804
2805static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002806create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002807 const char *filename)
2808{
2809 int fd;
2810 drm_magic_t magic;
2811
Giulio Camuffo954f1832014-10-11 18:27:30 +03002812 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002813 if (fd < 0)
2814 return NULL;
2815
2816 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002817 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002818
2819 return vaapi_recorder_create(fd, width, height, filename);
2820}
2821
2822static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002823recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2824 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002825{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002826 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002827 struct drm_output *output;
2828 int width, height;
2829
Giulio Camuffo954f1832014-10-11 18:27:30 +03002830 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002831 struct drm_output, base.link);
2832
2833 if (!output->recorder) {
Stefan Agner4a18f302019-10-20 18:25:42 +02002834 if (output->gbm_format != DRM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002835 weston_log("failed to start vaapi recorder: "
2836 "output format not supported\n");
2837 return;
2838 }
2839
Hardeningff39efa2013-09-18 23:56:35 +02002840 width = output->base.current_mode->width;
2841 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002842
2843 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002844 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002845 if (!output->recorder) {
2846 weston_log("failed to create vaapi recorder\n");
2847 return;
2848 }
2849
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302850 weston_output_disable_planes_incr(&output->base);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002851
2852 output->recorder_frame_listener.notify = recorder_frame_notify;
2853 wl_signal_add(&output->base.frame_signal,
2854 &output->recorder_frame_listener);
2855
2856 weston_output_schedule_repaint(&output->base);
2857
2858 weston_log("[libva recorder] initialized\n");
2859 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002860 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002861 }
2862}
2863#else
2864static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002865recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2866 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002867{
2868 weston_log("Compiled without libva support\n");
2869}
2870#endif
2871
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002872
Armin Krezović08368132016-09-30 14:11:05 +02002873static const struct weston_drm_output_api api = {
2874 drm_output_set_mode,
2875 drm_output_set_gbm_format,
2876 drm_output_set_seat,
2877};
2878
Giulio Camuffo954f1832014-10-11 18:27:30 +03002879static struct drm_backend *
2880drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002881 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002882{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002883 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01002884 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002885 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002886 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04002887 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02002888 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002889
nerdopolisb16c4ac2018-06-29 08:17:46 -04002890 session_seat = getenv("XDG_SEAT");
2891 if (session_seat)
2892 seat_id = session_seat;
2893
2894 if (config->seat_id)
2895 seat_id = config->seat_id;
2896
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002897 weston_log("initializing drm backend\n");
2898
Giulio Camuffo954f1832014-10-11 18:27:30 +03002899 b = zalloc(sizeof *b);
2900 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002901 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002902
Daniel Stone6020f472018-02-05 15:46:20 +00002903 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002904 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00002905 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002906
Giulio Camuffo954f1832014-10-11 18:27:30 +03002907 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002908 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002909 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02002910 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002911
Leandro Ribeiro172afc22019-12-26 16:23:43 -03002912 b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
2913 "Debug messages from DRM/KMS backend\n",
2914 NULL, NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002915
Pekka Paalanen7da9a382017-08-30 11:29:49 +03002916 compositor->backend = &b->base;
Leandro Ribeiroe57d8ae2020-05-06 18:10:19 -03002917 compositor->require_input = !config->continue_without_input;
Pekka Paalanen7da9a382017-08-30 11:29:49 +03002918
Stefan Agner0bfebeb2019-07-08 00:30:44 +02002919 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002920 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002921
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002922 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002923 compositor->launcher = weston_launcher_connect(compositor, config->tty,
2924 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002925 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02002926 weston_log("fatal: drm backend should be run using "
2927 "weston-launch binary, or your system should "
2928 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002929 goto err_compositor;
2930 }
2931
Giulio Camuffo954f1832014-10-11 18:27:30 +03002932 b->udev = udev_new();
2933 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002934 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002935 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002936 }
2937
Giulio Camuffo954f1832014-10-11 18:27:30 +03002938 b->session_listener.notify = session_notify;
2939 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002940
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002941 if (config->specific_device)
2942 drm_device = open_specific_drm_device(b, config->specific_device);
2943 else
2944 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002945 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002946 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002947 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002948 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002949
Daniel Stoneefa504f2016-12-19 16:48:20 +00002950 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002951 weston_log("failed to initialize kms\n");
2952 goto err_udev_dev;
2953 }
2954
Giulio Camuffo954f1832014-10-11 18:27:30 +03002955 if (b->use_pixman) {
2956 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002957 weston_log("failed to initialize pixman renderer\n");
2958 goto err_udev_dev;
2959 }
2960 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002961 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002962 weston_log("failed to initialize egl\n");
2963 goto err_udev_dev;
2964 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002965 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002966
Giulio Camuffo954f1832014-10-11 18:27:30 +03002967 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002968 b->base.repaint_begin = drm_repaint_begin;
2969 b->base.repaint_flush = drm_repaint_flush;
2970 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002971 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01002972 b->base.device_changed = drm_device_changed;
Marius Vlad81bada52019-11-11 00:27:17 +02002973 b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002974
Bob Ham91880f12016-01-12 10:21:47 +00002975 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002976
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002977 wl_list_init(&b->crtc_list);
2978 if (drm_backend_create_crtc_list(b) == -1) {
2979 weston_log("Failed to create CRTC list for DRM-backend\n");
2980 goto err_udev_dev;
2981 }
2982
Daniel Stone085d2b92015-05-21 00:00:57 +01002983 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002984 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002985
Giulio Camuffo954f1832014-10-11 18:27:30 +03002986 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03002987 compositor, b->udev, seat_id,
2988 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002989 weston_log("failed to create input devices\n");
2990 goto err_sprite;
2991 }
2992
Pekka Paalanend2e62422017-09-08 15:48:07 +03002993 if (drm_backend_create_heads(b, drm_device) < 0) {
2994 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002995 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002996 }
2997
Marius Vlade83e7502019-10-29 17:29:37 +02002998 /* 'compute' faked zpos values in case HW doesn't expose any */
2999 drm_backend_create_faked_zpos(b);
3000
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003001 /* A this point we have some idea of whether or not we have a working
3002 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003003 if (!b->cursors_are_broken)
3004 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003005
Giulio Camuffo954f1832014-10-11 18:27:30 +03003006 loop = wl_display_get_event_loop(compositor->wl_display);
3007 b->drm_source =
3008 wl_event_loop_add_fd(loop, b->drm.fd,
3009 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003010
Giulio Camuffo954f1832014-10-11 18:27:30 +03003011 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3012 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05003013 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003014 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003015 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003016 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003017 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003018 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003019 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003020 udev_monitor_get_fd(b->udev_monitor),
3021 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003022
Giulio Camuffo954f1832014-10-11 18:27:30 +03003023 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003024 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003025 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003026 }
3027
Daniel Stonea96b93c2012-06-22 14:04:37 +01003028 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003029
Giulio Camuffo954f1832014-10-11 18:27:30 +03003030 weston_compositor_add_debug_binding(compositor, KEY_O,
3031 planes_binding, b);
3032 weston_compositor_add_debug_binding(compositor, KEY_C,
3033 planes_binding, b);
3034 weston_compositor_add_debug_binding(compositor, KEY_V,
3035 planes_binding, b);
3036 weston_compositor_add_debug_binding(compositor, KEY_Q,
3037 recorder_binding, b);
3038 weston_compositor_add_debug_binding(compositor, KEY_W,
3039 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003040
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003041 if (compositor->renderer->import_dmabuf) {
3042 if (linux_dmabuf_setup(compositor) < 0)
3043 weston_log("Error: initializing dmabuf "
3044 "support failed.\n");
Marius Vladebd10e52019-11-16 19:22:48 +02003045 if (weston_direct_display_setup(compositor) < 0)
3046 weston_log("Error: initializing direct-display "
3047 "support failed.\n");
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003048 }
3049
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003050 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
3051 if (linux_explicit_synchronization_setup(compositor) < 0)
3052 weston_log("Error: initializing explicit "
3053 " synchronization support failed.\n");
3054 }
3055
Ankit Nautiyala344fe32019-05-14 18:36:08 +05303056 if (b->atomic_modeset)
3057 if (weston_compositor_enable_content_protection(compositor) < 0)
3058 weston_log("Error: initializing content-protection "
3059 "support failed.\n");
3060
Armin Krezović08368132016-09-30 14:11:05 +02003061 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
3062 &api, sizeof(api));
3063
3064 if (ret < 0) {
3065 weston_log("Failed to register output API.\n");
3066 goto err_udev_monitor;
3067 }
3068
Stefan Agner3654c672019-07-09 00:50:30 +02003069 ret = drm_backend_init_virtual_output_api(compositor);
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003070 if (ret < 0) {
3071 weston_log("Failed to register virtual output API.\n");
3072 goto err_udev_monitor;
3073 }
3074
Giulio Camuffo954f1832014-10-11 18:27:30 +03003075 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003076
3077err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003078 wl_event_source_remove(b->udev_drm_source);
3079 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003080err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003081 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003082err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003083 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003084err_sprite:
Stefan Agnerccf24072019-07-09 22:02:00 +02003085#ifdef BUILD_DRM_GBM
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01003086 if (b->gbm)
3087 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02003088#endif
Giulio Camuffo954f1832014-10-11 18:27:30 +03003089 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003090err_udev_dev:
3091 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003092err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003093 udev_unref(b->udev);
Marius Vlad5130a8c2020-07-30 14:47:32 +03003094err_launcher:
3095 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003096err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003097 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003098 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003099 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003100}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003101
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003102static void
3103config_init_to_defaults(struct weston_drm_backend_config *config)
3104{
Pekka Paalanendee412d2018-04-23 11:44:58 +02003105 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003106}
3107
Giulio Camuffo954f1832014-10-11 18:27:30 +03003108WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01003109weston_backend_init(struct weston_compositor *compositor,
3110 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003111{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003112 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003113 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003114
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003115 if (config_base == NULL ||
3116 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3117 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3118 weston_log("drm backend config structure is invalid\n");
3119 return -1;
3120 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02003121
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003122 config_init_to_defaults(&config);
3123 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003124
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003125 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003126 if (b == NULL)
3127 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003128
Giulio Camuffo954f1832014-10-11 18:27:30 +03003129 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003130}