blob: 2780f3bd797f71f71e5d8c75fac2d93fb5dcc8f7 [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. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100211 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500212}
213
Daniel Stone4c2fc702019-06-18 11:12:07 +0100214struct drm_output *
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000215drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
216{
217 struct drm_output *output;
218
219 wl_list_for_each(output, &b->compositor->output_list, base.link) {
220 if (output->crtc_id == crtc_id)
221 return output;
222 }
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
509drm_waitvblank_pipe(struct drm_output *output)
510{
511 if (output->pipe > 1)
512 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
513 DRM_VBLANK_HIGH_CRTC_MASK;
514 else if (output->pipe > 0)
515 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 */
555 vbl.request.type |= drm_waitvblank_pipe(output);
556 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 {
821 plane->possible_crtcs = (1 << output->pipe);
822 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
932 plane->possible_crtcs = (1 << output->pipe);
933 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);
1438 assert(output->crtc_id != 0);
1439 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
1440 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
1470static int
1471drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
1472{
1473 int i;
1474
1475 for (i = 0; i < resources->count_crtcs; i++) {
1476 if (resources->crtcs[i] == crtc_id)
1477 return i;
1478 }
1479
1480 assert(0 && "unknown crtc id");
1481 return -1;
1482}
1483
1484/** Pick a CRTC that might be able to drive all attached connectors
1485 *
1486 * @param output The output whose attached heads to include.
1487 * @param resources The DRM KMS resources.
1488 * @return CRTC index, or -1 on failure or not found.
1489 */
1490static int
1491drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
1492{
1493 struct drm_backend *backend;
1494 struct weston_head *base;
1495 struct drm_head *head;
1496 uint32_t possible_crtcs = 0xffffffff;
1497 int existing_crtc[32];
1498 unsigned j, n = 0;
1499 uint32_t crtc_id;
1500 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001501 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001502 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001503 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001504
1505 backend = to_drm_backend(output->base.compositor);
1506
1507 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
1508 * because it is more often set wrong than not in the kernel. */
1509
1510 /* Accumulate a mask of possible crtcs and find existing routings. */
1511 wl_list_for_each(base, &output->base.head_list, output_link) {
1512 head = to_drm_head(base);
1513
1514 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
1515
1516 crtc_id = head->inherited_crtc_id;
1517 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
1518 existing_crtc[n++] = drm_crtc_get_index(resources,
1519 crtc_id);
1520 }
1521
1522 /* Find a crtc that could drive each connector individually at least,
1523 * and prefer existing routings. */
1524 for (i = 0; i < resources->count_crtcs; i++) {
1525 crtc_id = resources->crtcs[i];
1526
1527 /* Could the crtc not drive each connector? */
1528 if (!(possible_crtcs & (1 << i)))
1529 continue;
1530
1531 /* Is the crtc already in use? */
1532 if (drm_output_find_by_crtc(backend, crtc_id))
1533 continue;
1534
1535 /* Try to preserve the existing CRTC -> connector routing;
1536 * it makes initialisation faster, and also since we have a
1537 * very dumb picking algorithm, may preserve a better
1538 * choice. */
1539 for (j = 0; j < n; j++) {
1540 if (existing_crtc[j] == i)
1541 return i;
1542 }
1543
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001544 /* Check if any other head had existing routing to this CRTC.
1545 * If they did, this is not the best CRTC as it might be needed
1546 * for another output we haven't enabled yet. */
1547 match = false;
1548 wl_list_for_each(base, &backend->compositor->head_list,
1549 compositor_link) {
1550 head = to_drm_head(base);
1551
1552 if (head->base.output == &output->base)
1553 continue;
1554
1555 if (weston_head_is_enabled(&head->base))
1556 continue;
1557
1558 if (head->inherited_crtc_id == crtc_id) {
1559 match = true;
1560 break;
1561 }
1562 }
1563 if (!match)
1564 best_crtc_index = i;
1565
1566 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001567 }
1568
1569 if (best_crtc_index != -1)
1570 return best_crtc_index;
1571
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001572 if (fallback_crtc_index != -1)
1573 return fallback_crtc_index;
1574
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001575 /* Likely possible_crtcs was empty due to asking for clones,
1576 * but since the DRM documentation says the kernel lies, let's
1577 * pick one crtc anyway. Trial and error is the only way to
1578 * be sure if something doesn't work. */
1579
1580 /* First pick any existing assignment. */
1581 for (j = 0; j < n; j++) {
1582 crtc_id = resources->crtcs[existing_crtc[j]];
1583 if (!drm_output_find_by_crtc(backend, crtc_id))
1584 return existing_crtc[j];
1585 }
1586
1587 /* Otherwise pick any available crtc. */
1588 for (i = 0; i < resources->count_crtcs; i++) {
1589 crtc_id = resources->crtcs[i];
1590
1591 if (!drm_output_find_by_crtc(backend, crtc_id))
1592 return i;
1593 }
1594
1595 return -1;
1596}
1597
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001598/** Allocate a CRTC for the output
1599 *
1600 * @param output The output with no allocated CRTC.
1601 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001602 * @return 0 on success, -1 on failure.
1603 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001604 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001605 * for the output, and loads the CRTC properties.
1606 *
1607 * Populates the cursor and scanout planes.
1608 *
1609 * On failure, the output remains without a CRTC.
1610 */
1611static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001612drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001613{
1614 struct drm_backend *b = to_drm_backend(output->base.compositor);
1615 drmModeObjectPropertiesPtr props;
1616 int i;
1617
1618 assert(output->crtc_id == 0);
1619
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001620 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001621 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001622 weston_log("Output '%s': No available CRTCs.\n",
1623 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001624 return -1;
1625 }
1626
1627 output->crtc_id = resources->crtcs[i];
1628 output->pipe = i;
1629
1630 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
1631 DRM_MODE_OBJECT_CRTC);
1632 if (!props) {
1633 weston_log("failed to get CRTC properties\n");
1634 goto err_crtc;
1635 }
1636 drm_property_info_populate(b, crtc_props, output->props_crtc,
1637 WDRM_CRTC__COUNT, props);
1638 drmModeFreeObjectProperties(props);
1639
1640 output->scanout_plane =
1641 drm_output_find_special_plane(b, output,
1642 WDRM_PLANE_TYPE_PRIMARY);
1643 if (!output->scanout_plane) {
1644 weston_log("Failed to find primary plane for output %s\n",
1645 output->base.name);
1646 goto err_crtc;
1647 }
1648
Tomohito Esaki51048462020-03-30 17:10:54 +09001649 /* Without universal planes, we can't discover which formats are
1650 * supported by the primary plane; we just hope that the GBM format
1651 * works. */
1652 if (!b->universal_planes)
1653 output->scanout_plane->formats[0].format = output->gbm_format;
1654
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001655 /* Failing to find a cursor plane is not fatal, as we'll fall back
1656 * to software cursor. */
1657 output->cursor_plane =
1658 drm_output_find_special_plane(b, output,
1659 WDRM_PLANE_TYPE_CURSOR);
1660
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001661 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
1662
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001663 return 0;
1664
1665err_crtc:
1666 output->crtc_id = 0;
1667 output->pipe = 0;
1668
1669 return -1;
1670}
1671
1672/** Free the CRTC from the output
1673 *
1674 * @param output The output whose CRTC to deallocate.
1675 *
1676 * The CRTC reserved for the given output becomes free to use again.
1677 */
1678static void
1679drm_output_fini_crtc(struct drm_output *output)
1680{
1681 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001682 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001683
Alexandros Frantzis53a71cb2020-05-18 15:26:01 +03001684 /* If the compositor is already shutting down, the planes have already
1685 * been destroyed. */
1686 if (!b->shutting_down) {
1687 if (!b->universal_planes) {
1688 /* Without universal planes, our special planes are
1689 * pseudo-planes allocated at output creation, freed at
1690 * output destruction, and not usable by other outputs.
1691 */
1692 if (output->cursor_plane)
1693 drm_plane_destroy(output->cursor_plane);
1694 if (output->scanout_plane)
1695 drm_plane_destroy(output->scanout_plane);
1696 } else {
1697 /* With universal planes, the 'special' planes are
1698 * allocated at startup, freed at shutdown, and live on
1699 * the plane list in between. We want the planes to
1700 * continue to exist and be freed up for other outputs.
1701 */
1702 if (output->cursor_plane)
1703 drm_plane_reset_state(output->cursor_plane);
1704 if (output->scanout_plane)
1705 drm_plane_reset_state(output->scanout_plane);
1706 }
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001707 }
1708
1709 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001710
1711 assert(output->crtc_id != 0);
1712
1713 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
1714 *unused = output->crtc_id;
1715
1716 /* Force resetting unused CRTCs */
1717 b->state_invalid = true;
1718
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001719 output->crtc_id = 0;
1720 output->cursor_plane = NULL;
1721 output->scanout_plane = NULL;
1722}
1723
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001724static int
Armin Krezović08368132016-09-30 14:11:05 +02001725drm_output_enable(struct weston_output *base)
1726{
1727 struct drm_output *output = to_drm_output(base);
1728 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001729 drmModeRes *resources;
1730 int ret;
1731
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001732 assert(!output->virtual);
1733
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001734 resources = drmModeGetResources(b->drm.fd);
1735 if (!resources) {
1736 weston_log("drmModeGetResources failed\n");
1737 return -1;
1738 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001739 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001740 drmModeFreeResources(resources);
1741 if (ret < 0)
1742 return -1;
1743
1744 if (drm_output_init_gamma_size(output) < 0)
1745 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02001746
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001747 if (b->pageflip_timeout)
1748 drm_output_pageflip_timer_create(output);
1749
Giulio Camuffo954f1832014-10-11 18:27:30 +03001750 if (b->use_pixman) {
1751 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001752 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00001753 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001754 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03001755 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001756 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00001757 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001758 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001759
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001760 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001761
Jonas Ådahle5a12252013-04-05 23:07:11 +02001762 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001763 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001764 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001765 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001766 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01001767 output->base.set_gamma = drm_output_set_gamma;
1768
Daniel Stone2ba17f42015-05-19 20:02:41 +01001769 if (output->cursor_plane)
1770 weston_compositor_stack_plane(b->compositor,
1771 &output->cursor_plane->base,
1772 NULL);
1773 else
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001774 b->cursors_are_broken = true;
Daniel Stone2ba17f42015-05-19 20:02:41 +01001775
Daniel Stonee2e80132018-01-16 15:37:33 +00001776 weston_compositor_stack_plane(b->compositor,
1777 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001778 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001779
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001780 weston_log("Output %s (crtc %d) video modes:\n",
1781 output->base.name, output->crtc_id);
1782 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001783
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001784 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001785
Daniel Stone02cf4662017-03-03 16:19:39 +00001786err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001787 drm_output_fini_crtc(output);
1788
David Herrmann0f0d54e2011-12-08 17:05:45 +01001789 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001790}
1791
Jesse Barnes58ef3792012-02-23 09:45:49 -05001792static void
Armin Krezović08368132016-09-30 14:11:05 +02001793drm_output_deinit(struct weston_output *base)
1794{
1795 struct drm_output *output = to_drm_output(base);
1796 struct drm_backend *b = to_drm_backend(base->compositor);
1797
Daniel Stone3e661f72016-11-04 17:24:06 +00001798 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02001799 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00001800 else
1801 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02001802
Daniel Stone2ba17f42015-05-19 20:02:41 +01001803 /* Since our planes are no longer in use anywhere, remove their base
1804 * weston_plane's link from the plane stacking list, unless we're
1805 * shutting down, in which case the plane has already been
1806 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00001807 if (!b->shutting_down) {
1808 wl_list_remove(&output->scanout_plane->base.link);
1809 wl_list_init(&output->scanout_plane->base.link);
1810
1811 if (output->cursor_plane) {
1812 wl_list_remove(&output->cursor_plane->base.link);
1813 wl_list_init(&output->cursor_plane->base.link);
1814 /* Turn off hardware cursor */
1815 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
1816 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01001817 }
Daniel Stone087ddf02017-02-14 17:51:30 +00001818
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001819 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02001820}
1821
1822static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03001823drm_head_destroy(struct drm_head *head);
1824
1825static void
Armin Krezović08368132016-09-30 14:11:05 +02001826drm_output_destroy(struct weston_output *base)
1827{
1828 struct drm_output *output = to_drm_output(base);
1829 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02001830
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001831 assert(!output->virtual);
1832
Daniel Stone31838bf2019-06-17 11:23:25 +01001833 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001834 output->destroy_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001835 weston_log("destroy output while page flip pending\n");
1836 return;
1837 }
1838
1839 if (output->base.enabled)
1840 drm_output_deinit(&output->base);
1841
Pekka Paalanen383b3af2017-09-11 14:40:48 +03001842 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02001843
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001844 if (output->pageflip_timer)
1845 wl_event_source_remove(output->pageflip_timer);
1846
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03001847 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02001848
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001849 assert(!output->state_last);
1850 drm_output_state_free(output->state_cur);
1851
Armin Krezović08368132016-09-30 14:11:05 +02001852 free(output);
1853}
1854
1855static int
1856drm_output_disable(struct weston_output *base)
1857{
1858 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02001859
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001860 assert(!output->virtual);
1861
Daniel Stone31838bf2019-06-17 11:23:25 +01001862 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001863 output->disable_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001864 return -1;
1865 }
1866
Daniel Stonea08512f2016-11-08 17:46:10 +00001867 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00001868
Armin Krezović08368132016-09-30 14:11:05 +02001869 if (output->base.enabled)
1870 drm_output_deinit(&output->base);
1871
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001872 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02001873
Armin Krezović08368132016-09-30 14:11:05 +02001874 return 0;
1875}
1876
1877/**
Daniel Stone087ddf02017-02-14 17:51:30 +00001878 * Update the list of unused connectors and CRTCs
1879 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03001880 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00001881 *
1882 * @param b Weston backend structure
1883 * @param resources DRM resources for this device
1884 */
1885static void
1886drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
1887{
1888 int i;
1889
Daniel Stone087ddf02017-02-14 17:51:30 +00001890 wl_array_release(&b->unused_crtcs);
1891 wl_array_init(&b->unused_crtcs);
1892
1893 for (i = 0; i < resources->count_crtcs; i++) {
1894 struct drm_output *output;
1895 uint32_t *crtc_id;
1896
1897 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
1898 if (output && output->base.enabled)
1899 continue;
1900
1901 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
1902 *crtc_id = resources->crtcs[i];
1903 }
1904}
1905
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301906/*
1907 * This function converts the protection status from drm values to
1908 * weston_hdcp_protection status. The drm values as read from the connector
1909 * properties "Content Protection" and "HDCP Content Type" need to be converted
1910 * to appropriate weston values, that can be sent to a client application.
1911 */
1912static int
1913get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
1914 enum wdrm_hdcp_content_type type,
1915 enum weston_hdcp_protection *weston_protection)
1916
1917{
1918 if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
1919 return -1;
1920 if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
1921 protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
1922 *weston_protection = WESTON_HDCP_DISABLE;
1923 return 0;
1924 }
1925 if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
1926 return -1;
1927 if (type == WDRM_HDCP_CONTENT_TYPE0) {
1928 *weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
1929 return 0;
1930 }
1931 if (type == WDRM_HDCP_CONTENT_TYPE1) {
1932 *weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
1933 return 0;
1934 }
1935 return -1;
1936}
1937
1938/**
1939 * Get current content-protection status for a given head.
1940 *
1941 * @param head drm_head, whose protection is to be retrieved
1942 * @param props drm property object of the connector, related to the head
1943 * @return protection status in case of success, -1 otherwise
1944 */
1945static enum weston_hdcp_protection
1946drm_head_get_current_protection(struct drm_head *head,
1947 drmModeObjectProperties *props)
1948{
1949 struct drm_property_info *info;
1950 enum wdrm_content_protection_state protection;
1951 enum wdrm_hdcp_content_type type;
1952 enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
1953
1954 info = &head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION];
1955 protection = drm_property_get_value(info, props,
1956 WDRM_CONTENT_PROTECTION__COUNT);
1957
1958 if (protection == WDRM_CONTENT_PROTECTION__COUNT)
1959 return WESTON_HDCP_DISABLE;
1960
1961 info = &head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
1962 type = drm_property_get_value(info, props,
1963 WDRM_HDCP_CONTENT_TYPE__COUNT);
1964
1965 /*
1966 * In case of platforms supporting HDCP1.4, only property
1967 * 'Content Protection' is exposed and not the 'HDCP Content Type'
1968 * for such cases HDCP Type 0 should be considered as the content-type.
1969 */
1970
1971 if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
1972 type = WDRM_HDCP_CONTENT_TYPE0;
1973
1974 if (get_weston_protection_from_drm(protection, type,
1975 &weston_hdcp) == -1) {
1976 weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
1977 protection, type, head->base.name,
1978 head->connector_id);
1979 return WESTON_HDCP_DISABLE;
1980 }
1981
1982 return weston_hdcp;
1983}
1984
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001985/** Replace connector data and monitor information
1986 *
1987 * @param head The head to update.
1988 * @param connector The connector data to be owned by the head, must match
1989 * the head's connector ID.
1990 * @return 0 on success, -1 on failure.
1991 *
1992 * Takes ownership of @c connector on success, not on failure.
1993 *
1994 * May schedule a heads changed call.
1995 */
1996static int
1997drm_head_assign_connector_info(struct drm_head *head,
1998 drmModeConnector *connector)
1999{
2000 drmModeObjectProperties *props;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002001
2002 assert(connector);
2003 assert(head->connector_id == connector->connector_id);
2004
2005 props = drmModeObjectGetProperties(head->backend->drm.fd,
2006 head->connector_id,
2007 DRM_MODE_OBJECT_CONNECTOR);
2008 if (!props) {
2009 weston_log("Error: failed to get connector '%s' properties\n",
2010 head->base.name);
2011 return -1;
2012 }
2013
2014 if (head->connector)
2015 drmModeFreeConnector(head->connector);
2016 head->connector = connector;
2017
2018 drm_property_info_populate(head->backend, connector_props,
2019 head->props_conn,
2020 WDRM_CONNECTOR__COUNT, props);
Daniel Stone3448cfc2019-06-26 22:56:39 +01002021 update_head_from_connector(head, props);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302022
2023 weston_head_set_content_protection_status(&head->base,
2024 drm_head_get_current_protection(head, props));
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002025 drmModeFreeObjectProperties(props);
2026
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002027 return 0;
2028}
2029
Pekka Paalanen456dc732017-11-09 15:10:11 +02002030static void
2031drm_head_log_info(struct drm_head *head, const char *msg)
2032{
2033 if (head->base.connected) {
2034 weston_log("DRM: head '%s' %s, connector %d is connected, "
2035 "EDID make '%s', model '%s', serial '%s'\n",
2036 head->base.name, msg, head->connector_id,
2037 head->base.make, head->base.model,
2038 head->base.serial_number ?: "");
2039 } else {
2040 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
2041 head->base.name, msg, head->connector_id);
2042 }
2043}
2044
Pekka Paalanend2e62422017-09-08 15:48:07 +03002045/** Update connector and monitor information
2046 *
2047 * @param head The head to update.
2048 *
2049 * Re-reads the DRM property lists for the connector and updates monitor
2050 * information and connection status. This may schedule a heads changed call
2051 * to the user.
2052 */
2053static void
2054drm_head_update_info(struct drm_head *head)
2055{
2056 drmModeConnector *connector;
2057
2058 connector = drmModeGetConnector(head->backend->drm.fd,
2059 head->connector_id);
2060 if (!connector) {
2061 weston_log("DRM: getting connector info for '%s' failed.\n",
2062 head->base.name);
2063 return;
2064 }
2065
2066 if (drm_head_assign_connector_info(head, connector) < 0)
2067 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002068
2069 if (head->base.device_changed)
2070 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03002071}
2072
Daniel Stone087ddf02017-02-14 17:51:30 +00002073/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03002074 * Create a Weston head for a connector
2075 *
2076 * Given a DRM connector, create a matching drm_head structure and add it
2077 * to Weston's head list.
2078 *
Marius Vlada2dace22019-06-12 16:05:44 +03002079 * @param backend Weston backend structure
Pekka Paalanenc112f002017-08-28 16:27:20 +03002080 * @param connector_id DRM connector ID for the head
2081 * @param drm_device udev device pointer
2082 * @returns The new head, or NULL on failure.
2083 */
2084static struct drm_head *
2085drm_head_create(struct drm_backend *backend, uint32_t connector_id,
2086 struct udev_device *drm_device)
2087{
2088 struct drm_head *head;
2089 drmModeConnector *connector;
2090 char *name;
2091
2092 head = zalloc(sizeof *head);
2093 if (!head)
2094 return NULL;
2095
2096 connector = drmModeGetConnector(backend->drm.fd, connector_id);
2097 if (!connector)
2098 goto err_alloc;
2099
2100 name = make_connector_name(connector);
2101 if (!name)
2102 goto err_alloc;
2103
2104 weston_head_init(&head->base, name);
2105 free(name);
2106
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002107 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002108 head->backend = backend;
2109
Pekka Paalanence724242017-09-04 12:21:24 +03002110 head->backlight = backlight_init(drm_device, connector->connector_type);
2111
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002112 if (drm_head_assign_connector_info(head, connector) < 0)
2113 goto err_init;
2114
2115 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
2116 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
2117 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002118
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02002119 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002120 weston_log("Failed to retrieve current mode from connector %d.\n",
2121 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02002122 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002123 }
2124
Pekka Paalanenc112f002017-08-28 16:27:20 +03002125 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002126 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03002127
2128 return head;
2129
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002130err_init:
2131 weston_head_release(&head->base);
2132
Pekka Paalanenc112f002017-08-28 16:27:20 +03002133err_alloc:
2134 if (connector)
2135 drmModeFreeConnector(connector);
2136
2137 free(head);
2138
2139 return NULL;
2140}
2141
2142static void
2143drm_head_destroy(struct drm_head *head)
2144{
2145 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03002146
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002147 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
2148 drmModeFreeConnector(head->connector);
2149
Pekka Paalanence724242017-09-04 12:21:24 +03002150 if (head->backlight)
2151 backlight_destroy(head->backlight);
2152
Pekka Paalanenc112f002017-08-28 16:27:20 +03002153 free(head);
2154}
2155
2156/**
Armin Krezović08368132016-09-30 14:11:05 +02002157 * Create a Weston output structure
2158 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002159 * Create an "empty" drm_output. This is the implementation of
2160 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02002161 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002162 * Creating an output is usually followed by drm_output_attach_head()
2163 * and drm_output_enable() to make use of it.
2164 *
2165 * @param compositor The compositor instance.
2166 * @param name Name for the new output.
2167 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02002168 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03002169static struct weston_output *
2170drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02002171{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002172 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02002173 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02002174
Armin Krezović08368132016-09-30 14:11:05 +02002175 output = zalloc(sizeof *output);
2176 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002177 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02002178
Daniel Stone64dbbee2018-07-20 19:00:06 +01002179 output->backend = b;
Stefan Agnerccf24072019-07-09 22:02:00 +02002180#ifdef BUILD_DRM_GBM
Tomohito Esaki718a40b2018-01-31 17:50:15 +09002181 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Stefan Agnerccf24072019-07-09 22:02:00 +02002182#endif
Daniel Stone64dbbee2018-07-20 19:00:06 +01002183
Pekka Paalanend2e62422017-09-08 15:48:07 +03002184 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002185
Armin Krezović08368132016-09-30 14:11:05 +02002186 output->base.enable = drm_output_enable;
2187 output->base.destroy = drm_output_destroy;
2188 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002189 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02002190 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02002191
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002192 output->destroy_pending = false;
2193 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02002194
Pekka Paalanen01f60212017-03-24 15:39:24 +02002195 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03002196
Armin Krezović08368132016-09-30 14:11:05 +02002197 weston_compositor_add_pending_output(&output->base, b->compositor);
2198
Pekka Paalanend2e62422017-09-08 15:48:07 +03002199 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02002200}
2201
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002202static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03002203drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002205 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002206 drmModeRes *resources;
2207 int i;
2208
Giulio Camuffo954f1832014-10-11 18:27:30 +03002209 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002210 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002211 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002212 return -1;
2213 }
2214
Giulio Camuffo954f1832014-10-11 18:27:30 +03002215 b->min_width = resources->min_width;
2216 b->max_width = resources->max_width;
2217 b->min_height = resources->min_height;
2218 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002219
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002220 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002221 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00002222
Pekka Paalanend2e62422017-09-08 15:48:07 +03002223 head = drm_head_create(b, connector_id, drm_device);
2224 if (!head) {
2225 weston_log("DRM: failed to create head for connector %d.\n",
2226 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002227 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002228 }
2229
Daniel Stone087ddf02017-02-14 17:51:30 +00002230 drm_backend_update_unused_outputs(b, resources);
2231
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002232 drmModeFreeResources(resources);
2233
2234 return 0;
2235}
2236
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002237static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03002238drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002239{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002240 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002241 struct weston_head *base, *next;
2242 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002243 int i;
2244
Giulio Camuffo954f1832014-10-11 18:27:30 +03002245 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002246 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002247 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002248 return;
2249 }
2250
Pekka Paalanend2e62422017-09-08 15:48:07 +03002251 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002252 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00002253 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02002254
Pekka Paalanend2e62422017-09-08 15:48:07 +03002255 head = drm_head_find_by_connector(b, connector_id);
2256 if (head) {
2257 drm_head_update_info(head);
2258 } else {
2259 head = drm_head_create(b, connector_id, drm_device);
2260 if (!head)
2261 weston_log("DRM: failed to create head for hot-added connector %d.\n",
2262 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002263 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002264 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002265
Pekka Paalanend2e62422017-09-08 15:48:07 +03002266 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03002267 wl_list_for_each_safe(base, next,
2268 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002269 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002270
Pekka Paalanena0a37462017-08-31 15:41:57 +03002271 head = to_drm_head(base);
2272
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002273 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002274 if (resources->connectors[i] == head->connector_id) {
2275 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002276 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002277 }
2278 }
Armin Krezović08368132016-09-30 14:11:05 +02002279
Pekka Paalanend2e62422017-09-08 15:48:07 +03002280 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002281 continue;
2282
Pekka Paalanend2e62422017-09-08 15:48:07 +03002283 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
2284 head->base.name, head->connector_id);
2285 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002286 }
2287
Daniel Stone087ddf02017-02-14 17:51:30 +00002288 drm_backend_update_unused_outputs(b, resources);
2289
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002290 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002291}
2292
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302293static enum wdrm_connector_property
2294drm_head_find_property_by_id(struct drm_head *head, uint32_t property_id)
2295{
2296 int i;
2297 enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
2298
2299 if (!head || !property_id)
2300 return WDRM_CONNECTOR__COUNT;
2301
2302 for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
2303 if (head->props_conn[i].prop_id == property_id) {
2304 prop = (enum wdrm_connector_property) i;
2305 break;
2306 }
2307 return prop;
2308}
2309
2310static void
2311drm_backend_update_conn_props(struct drm_backend *b,
2312 uint32_t connector_id,
2313 uint32_t property_id)
2314{
2315 struct drm_head *head;
2316 enum wdrm_connector_property conn_prop;
2317 drmModeObjectProperties *props;
2318
2319 head = drm_head_find_by_connector(b, connector_id);
2320 if (!head) {
2321 weston_log("DRM: failed to find head for connector id: %d.\n",
2322 connector_id);
2323 return;
2324 }
2325
2326 conn_prop = drm_head_find_property_by_id(head, property_id);
2327 if (conn_prop >= WDRM_CONNECTOR__COUNT)
2328 return;
2329
2330 props = drmModeObjectGetProperties(b->drm.fd,
2331 connector_id,
2332 DRM_MODE_OBJECT_CONNECTOR);
2333 if (!props) {
2334 weston_log("Error: failed to get connector '%s' properties\n",
2335 head->base.name);
2336 return;
2337 }
2338 if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
2339 weston_head_set_content_protection_status(&head->base,
2340 drm_head_get_current_protection(head, props));
2341 }
2342 drmModeFreeObjectProperties(props);
2343}
2344
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002345static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002346udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002347{
David Herrmannd7488c22012-03-11 20:05:21 +01002348 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002349 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002350
2351 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002352 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002353 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002354
David Herrmann6ac52db2012-03-11 20:05:22 +01002355 val = udev_device_get_property_value(device, "HOTPLUG");
2356 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002357 return 0;
2358
David Herrmann6ac52db2012-03-11 20:05:22 +01002359 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002360}
2361
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002362static int
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302363udev_event_is_conn_prop_change(struct drm_backend *b,
2364 struct udev_device *device,
2365 uint32_t *connector_id,
2366 uint32_t *property_id)
2367
2368{
2369 const char *val;
2370 int id;
2371
2372 val = udev_device_get_property_value(device, "CONNECTOR");
2373 if (!val || !safe_strtoint(val, &id))
2374 return 0;
2375 else
2376 *connector_id = id;
2377
2378 val = udev_device_get_property_value(device, "PROPERTY");
2379 if (!val || !safe_strtoint(val, &id))
2380 return 0;
2381 else
2382 *property_id = id;
2383
2384 return 1;
2385}
2386
2387static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002388udev_drm_event(int fd, uint32_t mask, void *data)
2389{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002390 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002391 struct udev_device *event;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302392 uint32_t conn_id, prop_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002393
Giulio Camuffo954f1832014-10-11 18:27:30 +03002394 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002395
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302396 if (udev_event_is_hotplug(b, event)) {
2397 if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
2398 drm_backend_update_conn_props(b, conn_id, prop_id);
2399 else
2400 drm_backend_update_heads(b, event);
2401 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002402
2403 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002404
2405 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002406}
2407
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002408static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002409drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002410{
Armin Krezović545dba62016-08-05 15:54:18 +02002411 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002412 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002413
Giulio Camuffo954f1832014-10-11 18:27:30 +03002414 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002415
Giulio Camuffo954f1832014-10-11 18:27:30 +03002416 wl_event_source_remove(b->udev_drm_source);
2417 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002418
Daniel Stoneb57c6a02017-10-05 16:27:21 +01002419 b->shutting_down = true;
2420
Giulio Camuffo954f1832014-10-11 18:27:30 +03002421 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002422
Leandro Ribeirof0149642019-12-18 15:52:18 -03002423 weston_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002424 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002425 weston_compositor_shutdown(ec);
2426
Pekka Paalanenc112f002017-08-28 16:27:20 +03002427 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
2428 drm_head_destroy(to_drm_head(base));
2429
Stefan Agnerccf24072019-07-09 22:02:00 +02002430#ifdef BUILD_DRM_GBM
Giulio Camuffo954f1832014-10-11 18:27:30 +03002431 if (b->gbm)
2432 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02002433#endif
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002434
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02002435 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03002436 udev_unref(b->udev);
2437
Giulio Camuffo954f1832014-10-11 18:27:30 +03002438 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002439
Daniel Stone087ddf02017-02-14 17:51:30 +00002440 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00002441
Giulio Camuffo954f1832014-10-11 18:27:30 +03002442 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02002443 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002444 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002445}
2446
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002447static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002448session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002449{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002450 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02002451 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01002452 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002453 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002454
Giulio Camuffo954f1832014-10-11 18:27:30 +03002455 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002456 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00002457 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002458 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00002459 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002460 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002461 } else {
2462 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002463 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002464
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002465 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002466
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002467 /* If we have a repaint scheduled (either from a
2468 * pending pageflip or the idle handler), make sure we
2469 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002470 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002471 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002472 * back, we schedule a repaint, which will process
2473 * pending frame callbacks. */
2474
Giulio Camuffo954f1832014-10-11 18:27:30 +03002475 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00002476 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002477 if (output->cursor_plane)
2478 drmModeSetCursor(b->drm.fd, output->crtc_id,
2479 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002480 }
2481
Giulio Camuffo954f1832014-10-11 18:27:30 +03002482 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002483 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002484
Daniel Stone085d2b92015-05-21 00:00:57 +01002485 wl_list_for_each(plane, &b->plane_list, link) {
2486 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
2487 continue;
2488
Giulio Camuffo954f1832014-10-11 18:27:30 +03002489 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01002490 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002491 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002492 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01002493 }
2494 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002495}
2496
Robert Beckett8d23ab72019-06-13 16:55:44 +01002497
2498/**
2499 * Handle KMS GPU being added/removed
2500 *
2501 * If the device being added/removed is the KMS device, we activate/deactivate
2502 * the compositor session.
2503 *
2504 * @param compositor The compositor instance.
2505 * @param device The device being added/removed.
2506 * @param added Whether the device is being added (or removed)
2507 */
2508static void
2509drm_device_changed(struct weston_compositor *compositor,
2510 dev_t device, bool added)
2511{
2512 struct drm_backend *b = to_drm_backend(compositor);
2513
Robert Beckett49dc3202019-07-02 16:31:22 +01002514 if (b->drm.fd < 0 || b->drm.devnum != device ||
2515 compositor->session_active == added)
Robert Beckett8d23ab72019-06-13 16:55:44 +01002516 return;
2517
2518 compositor->session_active = added;
2519 wl_signal_emit(&compositor->session_signal, compositor);
2520}
2521
Daniel Stoneefa504f2016-12-19 16:48:20 +00002522/**
2523 * Determines whether or not a device is capable of modesetting. If successful,
2524 * sets b->drm.fd and b->drm.filename to the opened device.
2525 */
2526static bool
2527drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2528{
2529 const char *filename = udev_device_get_devnode(device);
2530 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002531 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002532 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02002533 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002534
2535 if (!filename)
2536 return false;
2537
2538 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
2539 if (fd < 0)
2540 return false;
2541
2542 res = drmModeGetResources(fd);
2543 if (!res)
2544 goto out_fd;
2545
2546 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2547 res->count_encoders <= 0)
2548 goto out_res;
2549
2550 if (sysnum)
2551 id = atoi(sysnum);
2552 if (!sysnum || id < 0) {
2553 weston_log("couldn't get sysnum for device %s\n", filename);
2554 goto out_res;
2555 }
2556
2557 /* We can be called successfully on multiple devices; if we have,
2558 * clean up old entries. */
2559 if (b->drm.fd >= 0)
2560 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2561 free(b->drm.filename);
2562
2563 b->drm.fd = fd;
2564 b->drm.id = id;
2565 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002566 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002567
Sergi Granellceb59812017-03-28 12:44:04 +02002568 drmModeFreeResources(res);
2569
Daniel Stoneefa504f2016-12-19 16:48:20 +00002570 return true;
2571
2572out_res:
2573 drmModeFreeResources(res);
2574out_fd:
2575 weston_launcher_close(b->compositor->launcher, fd);
2576 return false;
2577}
2578
David Herrmann0af066f2012-10-29 19:21:16 +01002579/*
2580 * Find primary GPU
2581 * Some systems may have multiple DRM devices attached to a single seat. This
2582 * function loops over all devices and tries to find a PCI device with the
2583 * boot_vga sysfs attribute set to 1.
2584 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00002585 * Devices are also vetted to make sure they are are capable of modesetting,
2586 * rather than pure render nodes (GPU with no display), or pure
2587 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01002588 */
2589static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002590find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002591{
2592 struct udev_enumerate *e;
2593 struct udev_list_entry *entry;
2594 const char *path, *device_seat, *id;
2595 struct udev_device *device, *drm_device, *pci;
2596
Giulio Camuffo954f1832014-10-11 18:27:30 +03002597 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002598 udev_enumerate_add_match_subsystem(e, "drm");
2599 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2600
2601 udev_enumerate_scan_devices(e);
2602 drm_device = NULL;
2603 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00002604 bool is_boot_vga = false;
2605
David Herrmann0af066f2012-10-29 19:21:16 +01002606 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002607 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002608 if (!device)
2609 continue;
2610 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2611 if (!device_seat)
2612 device_seat = default_seat;
2613 if (strcmp(device_seat, seat)) {
2614 udev_device_unref(device);
2615 continue;
2616 }
2617
2618 pci = udev_device_get_parent_with_subsystem_devtype(device,
2619 "pci", NULL);
2620 if (pci) {
2621 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00002622 if (id && !strcmp(id, "1"))
2623 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01002624 }
2625
Daniel Stoneefa504f2016-12-19 16:48:20 +00002626 /* If we already have a modesetting-capable device, and this
2627 * device isn't our boot-VGA device, we aren't going to use
2628 * it. */
2629 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01002630 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002631 continue;
2632 }
2633
2634 /* Make sure this device is actually capable of modesetting;
2635 * if this call succeeds, b->drm.{fd,filename} will be set,
2636 * and any old values freed. */
2637 if (!drm_device_is_kms(b, device)) {
2638 udev_device_unref(device);
2639 continue;
2640 }
2641
2642 /* There can only be one boot_vga device, and we try to use it
2643 * at all costs. */
2644 if (is_boot_vga) {
2645 if (drm_device)
2646 udev_device_unref(drm_device);
2647 drm_device = device;
2648 break;
2649 }
2650
2651 /* Per the (!is_boot_vga && drm_device) test above, we only
2652 * trump existing saved devices with boot-VGA devices, so if
2653 * we end up here, this must be the first device we've seen. */
2654 assert(!drm_device);
2655 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01002656 }
2657
Daniel Stoneefa504f2016-12-19 16:48:20 +00002658 /* If we're returning a device to use, we must have an open FD for
2659 * it. */
2660 assert(!!drm_device == (b->drm.fd >= 0));
2661
David Herrmann0af066f2012-10-29 19:21:16 +01002662 udev_enumerate_unref(e);
2663 return drm_device;
2664}
2665
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002666static struct udev_device *
2667open_specific_drm_device(struct drm_backend *b, const char *name)
2668{
2669 struct udev_device *device;
2670
2671 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2672 if (!device) {
2673 weston_log("ERROR: could not open DRM device '%s'\n", name);
2674 return NULL;
2675 }
2676
2677 if (!drm_device_is_kms(b, device)) {
2678 udev_device_unref(device);
2679 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2680 return NULL;
2681 }
2682
2683 /* If we're returning a device to use, we must have an open FD for
2684 * it. */
2685 assert(b->drm.fd >= 0);
2686
2687 return device;
2688}
2689
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002690static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002691planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2692 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002693{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002694 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002695
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002696 switch (key) {
2697 case KEY_C:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002698 b->cursors_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002699 break;
2700 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01002701 /* We don't support overlay-plane usage with legacy KMS. */
2702 if (b->atomic_modeset)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002703 b->sprites_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002704 break;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002705 default:
2706 break;
2707 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002708}
2709
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002710#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002711static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002712recorder_destroy(struct drm_output *output)
2713{
2714 vaapi_recorder_destroy(output->recorder);
2715 output->recorder = NULL;
2716
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302717 weston_output_disable_planes_decr(&output->base);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002718
2719 wl_list_remove(&output->recorder_frame_listener.link);
2720 weston_log("[libva recorder] done\n");
2721}
2722
2723static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002724recorder_frame_notify(struct wl_listener *listener, void *data)
2725{
2726 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002727 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002728 int fd, ret;
2729
2730 output = container_of(listener, struct drm_output,
2731 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02002732 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002733
2734 if (!output->recorder)
2735 return;
2736
Daniel Stonee2e80132018-01-16 15:37:33 +00002737 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002738 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002739 DRM_CLOEXEC, &fd);
2740 if (ret) {
2741 weston_log("[libva recorder] "
2742 "failed to create prime fd for front buffer\n");
2743 return;
2744 }
2745
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002746 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002747 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002748 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002749 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002750 recorder_destroy(output);
2751 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002752}
2753
2754static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002755create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002756 const char *filename)
2757{
2758 int fd;
2759 drm_magic_t magic;
2760
Giulio Camuffo954f1832014-10-11 18:27:30 +03002761 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002762 if (fd < 0)
2763 return NULL;
2764
2765 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002766 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002767
2768 return vaapi_recorder_create(fd, width, height, filename);
2769}
2770
2771static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002772recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2773 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002774{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002775 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002776 struct drm_output *output;
2777 int width, height;
2778
Giulio Camuffo954f1832014-10-11 18:27:30 +03002779 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002780 struct drm_output, base.link);
2781
2782 if (!output->recorder) {
Stefan Agner4a18f302019-10-20 18:25:42 +02002783 if (output->gbm_format != DRM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002784 weston_log("failed to start vaapi recorder: "
2785 "output format not supported\n");
2786 return;
2787 }
2788
Hardeningff39efa2013-09-18 23:56:35 +02002789 width = output->base.current_mode->width;
2790 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002791
2792 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002793 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002794 if (!output->recorder) {
2795 weston_log("failed to create vaapi recorder\n");
2796 return;
2797 }
2798
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302799 weston_output_disable_planes_incr(&output->base);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002800
2801 output->recorder_frame_listener.notify = recorder_frame_notify;
2802 wl_signal_add(&output->base.frame_signal,
2803 &output->recorder_frame_listener);
2804
2805 weston_output_schedule_repaint(&output->base);
2806
2807 weston_log("[libva recorder] initialized\n");
2808 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002809 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002810 }
2811}
2812#else
2813static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002814recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2815 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002816{
2817 weston_log("Compiled without libva support\n");
2818}
2819#endif
2820
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002821
Armin Krezović08368132016-09-30 14:11:05 +02002822static const struct weston_drm_output_api api = {
2823 drm_output_set_mode,
2824 drm_output_set_gbm_format,
2825 drm_output_set_seat,
2826};
2827
Giulio Camuffo954f1832014-10-11 18:27:30 +03002828static struct drm_backend *
2829drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002830 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002831{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002832 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01002833 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002834 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002835 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04002836 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02002837 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002838
nerdopolisb16c4ac2018-06-29 08:17:46 -04002839 session_seat = getenv("XDG_SEAT");
2840 if (session_seat)
2841 seat_id = session_seat;
2842
2843 if (config->seat_id)
2844 seat_id = config->seat_id;
2845
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002846 weston_log("initializing drm backend\n");
2847
Giulio Camuffo954f1832014-10-11 18:27:30 +03002848 b = zalloc(sizeof *b);
2849 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002850 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002851
Daniel Stone6020f472018-02-05 15:46:20 +00002852 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002853 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00002854 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002855
Giulio Camuffo954f1832014-10-11 18:27:30 +03002856 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002857 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002858 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02002859 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002860
Leandro Ribeiro172afc22019-12-26 16:23:43 -03002861 b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
2862 "Debug messages from DRM/KMS backend\n",
2863 NULL, NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002864
Pekka Paalanen7da9a382017-08-30 11:29:49 +03002865 compositor->backend = &b->base;
Leandro Ribeiroe57d8ae2020-05-06 18:10:19 -03002866 compositor->require_input = !config->continue_without_input;
Pekka Paalanen7da9a382017-08-30 11:29:49 +03002867
Stefan Agner0bfebeb2019-07-08 00:30:44 +02002868 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002869 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002870
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002871 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002872 compositor->launcher = weston_launcher_connect(compositor, config->tty,
2873 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002874 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02002875 weston_log("fatal: drm backend should be run using "
2876 "weston-launch binary, or your system should "
2877 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002878 goto err_compositor;
2879 }
2880
Giulio Camuffo954f1832014-10-11 18:27:30 +03002881 b->udev = udev_new();
2882 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002883 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002884 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002885 }
2886
Giulio Camuffo954f1832014-10-11 18:27:30 +03002887 b->session_listener.notify = session_notify;
2888 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002889
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002890 if (config->specific_device)
2891 drm_device = open_specific_drm_device(b, config->specific_device);
2892 else
2893 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002894 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002895 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002896 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002897 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002898
Daniel Stoneefa504f2016-12-19 16:48:20 +00002899 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002900 weston_log("failed to initialize kms\n");
2901 goto err_udev_dev;
2902 }
2903
Giulio Camuffo954f1832014-10-11 18:27:30 +03002904 if (b->use_pixman) {
2905 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002906 weston_log("failed to initialize pixman renderer\n");
2907 goto err_udev_dev;
2908 }
2909 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002910 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002911 weston_log("failed to initialize egl\n");
2912 goto err_udev_dev;
2913 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002914 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002915
Giulio Camuffo954f1832014-10-11 18:27:30 +03002916 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002917 b->base.repaint_begin = drm_repaint_begin;
2918 b->base.repaint_flush = drm_repaint_flush;
2919 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002920 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01002921 b->base.device_changed = drm_device_changed;
Marius Vlad81bada52019-11-11 00:27:17 +02002922 b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002923
Bob Ham91880f12016-01-12 10:21:47 +00002924 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002925
Daniel Stone085d2b92015-05-21 00:00:57 +01002926 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002927 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002928
Giulio Camuffo954f1832014-10-11 18:27:30 +03002929 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03002930 compositor, b->udev, seat_id,
2931 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002932 weston_log("failed to create input devices\n");
2933 goto err_sprite;
2934 }
2935
Pekka Paalanend2e62422017-09-08 15:48:07 +03002936 if (drm_backend_create_heads(b, drm_device) < 0) {
2937 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002938 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002939 }
2940
Marius Vlade83e7502019-10-29 17:29:37 +02002941 /* 'compute' faked zpos values in case HW doesn't expose any */
2942 drm_backend_create_faked_zpos(b);
2943
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002944 /* A this point we have some idea of whether or not we have a working
2945 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002946 if (!b->cursors_are_broken)
2947 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002948
Giulio Camuffo954f1832014-10-11 18:27:30 +03002949 loop = wl_display_get_event_loop(compositor->wl_display);
2950 b->drm_source =
2951 wl_event_loop_add_fd(loop, b->drm.fd,
2952 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002953
Giulio Camuffo954f1832014-10-11 18:27:30 +03002954 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
2955 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002956 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002957 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002958 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002959 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002960 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002961 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002962 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002963 udev_monitor_get_fd(b->udev_monitor),
2964 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002965
Giulio Camuffo954f1832014-10-11 18:27:30 +03002966 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002967 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002968 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002969 }
2970
Daniel Stonea96b93c2012-06-22 14:04:37 +01002971 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002972
Giulio Camuffo954f1832014-10-11 18:27:30 +03002973 weston_compositor_add_debug_binding(compositor, KEY_O,
2974 planes_binding, b);
2975 weston_compositor_add_debug_binding(compositor, KEY_C,
2976 planes_binding, b);
2977 weston_compositor_add_debug_binding(compositor, KEY_V,
2978 planes_binding, b);
2979 weston_compositor_add_debug_binding(compositor, KEY_Q,
2980 recorder_binding, b);
2981 weston_compositor_add_debug_binding(compositor, KEY_W,
2982 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002983
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002984 if (compositor->renderer->import_dmabuf) {
2985 if (linux_dmabuf_setup(compositor) < 0)
2986 weston_log("Error: initializing dmabuf "
2987 "support failed.\n");
Marius Vladebd10e52019-11-16 19:22:48 +02002988 if (weston_direct_display_setup(compositor) < 0)
2989 weston_log("Error: initializing direct-display "
2990 "support failed.\n");
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002991 }
2992
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002993 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
2994 if (linux_explicit_synchronization_setup(compositor) < 0)
2995 weston_log("Error: initializing explicit "
2996 " synchronization support failed.\n");
2997 }
2998
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302999 if (b->atomic_modeset)
3000 if (weston_compositor_enable_content_protection(compositor) < 0)
3001 weston_log("Error: initializing content-protection "
3002 "support failed.\n");
3003
Armin Krezović08368132016-09-30 14:11:05 +02003004 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
3005 &api, sizeof(api));
3006
3007 if (ret < 0) {
3008 weston_log("Failed to register output API.\n");
3009 goto err_udev_monitor;
3010 }
3011
Stefan Agner3654c672019-07-09 00:50:30 +02003012 ret = drm_backend_init_virtual_output_api(compositor);
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003013 if (ret < 0) {
3014 weston_log("Failed to register virtual output API.\n");
3015 goto err_udev_monitor;
3016 }
3017
Giulio Camuffo954f1832014-10-11 18:27:30 +03003018 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003019
3020err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003021 wl_event_source_remove(b->udev_drm_source);
3022 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003023err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003024 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003025err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003026 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003027err_sprite:
Stefan Agnerccf24072019-07-09 22:02:00 +02003028#ifdef BUILD_DRM_GBM
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01003029 if (b->gbm)
3030 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02003031#endif
Giulio Camuffo954f1832014-10-11 18:27:30 +03003032 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003033err_udev_dev:
3034 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003035err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003036 udev_unref(b->udev);
Marius Vlad5130a8c2020-07-30 14:47:32 +03003037err_launcher:
3038 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003039err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003040 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003041 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003042 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003043}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003044
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003045static void
3046config_init_to_defaults(struct weston_drm_backend_config *config)
3047{
Pekka Paalanendee412d2018-04-23 11:44:58 +02003048 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003049}
3050
Giulio Camuffo954f1832014-10-11 18:27:30 +03003051WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01003052weston_backend_init(struct weston_compositor *compositor,
3053 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003054{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003055 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003056 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003057
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003058 if (config_base == NULL ||
3059 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3060 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3061 weston_log("drm backend config structure is invalid\n");
3062 return -1;
3063 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02003064
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003065 config_init_to_defaults(&config);
3066 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003067
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003068 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003069 if (b == NULL)
3070 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003071
Giulio Camuffo954f1832014-10-11 18:27:30 +03003072 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003073}