blob: d495c24c44443985c175447833c17cfbd7b9a551 [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);
Daniel Stonea08512f2016-11-08 17:46:10 +0000309 } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
310 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
311 /* DPMS can happen to us either in the middle of a repaint
312 * cycle (when we have painted fresh content, only to throw it
313 * away for DPMS off), or at any other random point. If the
314 * latter is true, then we cannot go through finish_frame,
315 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000316 return;
317 }
318
319 ts.tv_sec = sec;
320 ts.tv_nsec = usec * 1000;
321 weston_output_finish_frame(&output->base, &ts, flags);
322
323 /* We can't call this from frame_notify, because the output's
324 * repaint needed flag is cleared just after that */
325 if (output->recorder)
326 weston_output_schedule_repaint(&output->base);
327}
328
Daniel Stone95d48a22017-04-04 17:54:30 +0100329static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000330drm_output_render_pixman(struct drm_output_state *state,
331 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200332{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000333 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200334 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200335
336 output->current_image ^= 1;
337
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200338 pixman_renderer_output_set_buffer(&output->base,
339 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200340 pixman_renderer_output_set_hw_extra_damage(&output->base,
341 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200342
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200343 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200344
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200345 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +0100346
347 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200348}
349
Stefan Agner3654c672019-07-09 00:50:30 +0200350void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000351drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200352{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000353 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300354 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +0000355 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +0000356 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +0200357 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +0100358 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200359
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100360 /* If we already have a client buffer promoted to scanout, then we don't
361 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +0000362 scanout_state = drm_output_state_get_plane(state,
363 output->scanout_plane);
364 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100365 return;
366
Daniel Stonee95169b2016-11-14 17:46:59 +0000367 if (!pixman_region32_not_empty(damage) &&
368 scanout_plane->state_cur->fb &&
369 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
370 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
371 scanout_plane->state_cur->fb->width ==
372 output->base.current_mode->width &&
373 scanout_plane->state_cur->fb->height ==
374 output->base.current_mode->height) {
375 fb = drm_fb_ref(scanout_plane->state_cur->fb);
376 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000377 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000378 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000379 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000380 }
Daniel Stone95d48a22017-04-04 17:54:30 +0100381
Daniel Stonee2e80132018-01-16 15:37:33 +0000382 if (!fb) {
383 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +0100384 return;
Daniel Stonee2e80132018-01-16 15:37:33 +0000385 }
386
387 scanout_state->fb = fb;
388 scanout_state->output = output;
389
390 scanout_state->src_x = 0;
391 scanout_state->src_y = 0;
392 scanout_state->src_w = output->base.current_mode->width << 16;
393 scanout_state->src_h = output->base.current_mode->height << 16;
394
395 scanout_state->dest_x = 0;
396 scanout_state->dest_y = 0;
397 scanout_state->dest_w = scanout_state->src_w >> 16;
398 scanout_state->dest_h = scanout_state->src_h >> 16;
399
Deepak Rawat46a1c722018-07-24 14:13:34 -0700400 pixman_region32_copy(&scanout_state->damage, damage);
401 if (output->base.zoom.active) {
402 weston_matrix_transform_region(&scanout_state->damage,
403 &output->base.matrix,
404 &scanout_state->damage);
405 } else {
406 pixman_region32_translate(&scanout_state->damage,
407 -output->base.x, -output->base.y);
408 weston_transformed_region(output->base.width,
409 output->base.height,
410 output->base.transform,
411 output->base.current_scale,
412 &scanout_state->damage,
413 &scanout_state->damage);
414 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200415
Giulio Camuffo954f1832014-10-11 18:27:30 +0300416 pixman_region32_subtract(&c->primary_plane.damage,
417 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200418}
419
Daniel Stonea08512f2016-11-08 17:46:10 +0000420static int
421drm_output_repaint(struct weston_output *output_base,
422 pixman_region32_t *damage,
423 void *repaint_data)
424{
425 struct drm_pending_state *pending_state = repaint_data;
426 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +0000427 struct drm_output_state *state = NULL;
428 struct drm_plane_state *scanout_state;
429
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900430 assert(!output->virtual);
431
Daniel Stonea08512f2016-11-08 17:46:10 +0000432 if (output->disable_pending || output->destroy_pending)
433 goto err;
434
435 assert(!output->state_last);
436
437 /* If planes have been disabled in the core, we might not have
438 * hit assign_planes at all, so might not have valid output state
439 * here. */
440 state = drm_pending_state_get_output(pending_state, output);
441 if (!state)
442 state = drm_output_state_duplicate(output->state_cur,
443 pending_state,
444 DRM_OUTPUT_STATE_CLEAR_PLANES);
445 state->dpms = WESTON_DPMS_ON;
446
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530447 if (output_base->allow_protection)
448 state->protection = output_base->desired_protection;
449 else
450 state->protection = WESTON_HDCP_DISABLE;
451
Daniel Stonea08512f2016-11-08 17:46:10 +0000452 drm_output_render(state, damage);
453 scanout_state = drm_output_state_get_plane(state,
454 output->scanout_plane);
455 if (!scanout_state || !scanout_state->fb)
456 goto err;
457
Daniel Stonea08512f2016-11-08 17:46:10 +0000458 return 0;
459
460err:
461 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +0200462 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400463}
464
Daniel Stone4c2fc702019-06-18 11:12:07 +0100465/* Determine the type of vblank synchronization to use for the output.
466 *
467 * The pipe parameter indicates which CRTC is in use. Knowing this, we
468 * can determine which vblank sequence type to use for it. Traditional
469 * cards had only two CRTCs, with CRTC 0 using no special flags, and
470 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
471 * parameter indicates this.
472 *
473 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
474 * 0-31. If this is non-zero it indicates we're dealing with a
475 * multi-gpu situation and we need to calculate the vblank sync
476 * using DRM_BLANK_HIGH_CRTC_MASK.
477 */
478static unsigned int
479drm_waitvblank_pipe(struct drm_output *output)
480{
481 if (output->pipe > 1)
482 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
483 DRM_VBLANK_HIGH_CRTC_MASK;
484 else if (output->pipe > 0)
485 return DRM_VBLANK_SECONDARY;
486 else
487 return 0;
488}
489
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200490static int
Jonas Ådahle5a12252013-04-05 23:07:11 +0200491drm_output_start_repaint_loop(struct weston_output *output_base)
492{
Armin Krezović545dba62016-08-05 15:54:18 +0200493 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +0000494 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +0000495 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +0200496 struct drm_backend *backend =
497 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200498 struct timespec ts, tnow;
499 struct timespec vbl2now;
500 int64_t refresh_nsec;
501 int ret;
502 drmVBlank vbl = {
503 .request.type = DRM_VBLANK_RELATIVE,
504 .request.sequence = 0,
505 .request.signal = 0,
506 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300507
Armin Krezović08368132016-09-30 14:11:05 +0200508 if (output->disable_pending || output->destroy_pending)
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200509 return 0;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800510
Daniel Stonee2e80132018-01-16 15:37:33 +0000511 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300512 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200513 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300514 }
515
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300516 /* Need to smash all state in from scratch; current timings might not
517 * be what we want, page flip might not work, etc.
518 */
Daniel Stone6020f472018-02-05 15:46:20 +0000519 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300520 goto finish_frame;
521
Daniel Stonee2e80132018-01-16 15:37:33 +0000522 assert(scanout_plane->state_cur->output == output);
523
Mario Kleinerf507ec32015-06-21 21:25:14 +0200524 /* Try to get current msc and timestamp via instant query */
525 vbl.request.type |= drm_waitvblank_pipe(output);
526 ret = drmWaitVBlank(backend->drm.fd, &vbl);
527
528 /* Error ret or zero timestamp means failure to get valid timestamp */
529 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
530 ts.tv_sec = vbl.reply.tval_sec;
531 ts.tv_nsec = vbl.reply.tval_usec * 1000;
532
533 /* Valid timestamp for most recent vblank - not stale?
534 * Stale ts could happen on Linux 3.17+, so make sure it
535 * is not older than 1 refresh duration since now.
536 */
537 weston_compositor_read_presentation_clock(backend->compositor,
538 &tnow);
539 timespec_sub(&vbl2now, &tnow, &ts);
540 refresh_nsec =
541 millihz_to_nsec(output->base.current_mode->refresh);
542 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
543 drm_output_update_msc(output, vbl.reply.sequence);
544 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200545 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200546 return 0;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200547 }
548 }
549
550 /* Immediate query didn't provide valid timestamp.
551 * Use pageflip fallback.
552 */
Jonas Ådahle5a12252013-04-05 23:07:11 +0200553
Daniel Stone205c0a02017-04-04 17:54:33 +0100554 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000555 assert(!output->state_last);
556
557 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +0000558 drm_output_state_duplicate(output->state_cur, pending_state,
559 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +0100560
Daniel Stone8747f952016-11-29 20:17:32 +0000561 ret = drm_pending_state_apply(pending_state);
562 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200563 weston_log("applying repaint-start state failed: %s\n",
564 strerror(errno));
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200565 if (ret == -EACCES)
566 return -1;
David Herrmann3c688c52013-10-22 17:11:25 +0200567 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200568 }
David Herrmann3c688c52013-10-22 17:11:25 +0200569
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200570 return 0;
David Herrmann3c688c52013-10-22 17:11:25 +0200571
572finish_frame:
573 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +0000574 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200575 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200576 return 0;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200577}
578
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000579/**
580 * Begin a new repaint cycle
581 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000582 * Called by the core compositor at the beginning of a repaint cycle. Creates
583 * a new pending_state structure to own any output state created by individual
584 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000585 */
586static void *
587drm_repaint_begin(struct weston_compositor *compositor)
588{
589 struct drm_backend *b = to_drm_backend(compositor);
590 struct drm_pending_state *ret;
591
592 ret = drm_pending_state_alloc(b);
593 b->repaint_data = ret;
594
Marius Vlad7e4db952019-04-17 13:47:06 +0300595 if (weston_log_scope_is_enabled(b->debug)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100596 char *dbg = weston_compositor_print_scene_graph(compositor);
597 drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
598 ret);
599 drm_debug(b, "%s", dbg);
600 free(dbg);
601 }
602
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000603 return ret;
604}
605
606/**
607 * Flush a repaint set
608 *
609 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000610 * and should be flushed. Frees the pending state, transitioning ownership
611 * of the output state from the pending state, to the update itself. When
612 * the update completes (see drm_output_update_complete), the output
613 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000614 */
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200615static int
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000616drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
617{
618 struct drm_backend *b = to_drm_backend(compositor);
619 struct drm_pending_state *pending_state = repaint_data;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200620 int ret;
Daniel Stone6020f472018-02-05 15:46:20 +0000621
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200622 ret = drm_pending_state_apply(pending_state);
623 if (ret != 0)
624 weston_log("repaint-flush failed: %s\n", strerror(errno));
625
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100626 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000627 b->repaint_data = NULL;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200628
629 return (ret == -EACCES) ? -1 : 0;
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000630}
631
632/**
633 * Cancel a repaint set
634 *
635 * Called by the core compositor when a repaint has finished, so the data
636 * held across the repaint cycle should be discarded.
637 */
638static void
639drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
640{
641 struct drm_backend *b = to_drm_backend(compositor);
642 struct drm_pending_state *pending_state = repaint_data;
643
644 drm_pending_state_free(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100645 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000646 b->repaint_data = NULL;
647}
648
Alex Wub7b8bda2012-04-17 17:20:48 +0800649static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300650drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +0000651static void
652drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200653
654static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800655drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
656{
Daniel Stone02d487a2017-10-07 14:01:45 +0100657 struct drm_output *output = to_drm_output(output_base);
658 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stonefbe6c1d2019-06-17 16:04:26 +0100659 struct drm_mode *drm_mode = drm_output_choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +0800660
661 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +0100662 weston_log("%s: invalid resolution %dx%d\n",
663 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800664 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200665 }
666
Hardeningff39efa2013-09-18 23:56:35 +0200667 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +0800668 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800669
Hardeningff39efa2013-09-18 23:56:35 +0200670 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800671
Hardeningff39efa2013-09-18 23:56:35 +0200672 output->base.current_mode = &drm_mode->base;
673 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800674 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
675
Daniel Stonef30a18c2017-04-04 17:54:31 +0100676 /* XXX: This drops our current buffer too early, before we've started
677 * displaying it. Ideally this should be much more atomic and
678 * integrated with a full repaint cycle, rather than doing a
679 * sledgehammer modeswitch first, and only later showing new
680 * content.
681 */
Daniel Stone6020f472018-02-05 15:46:20 +0000682 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +0800683
Giulio Camuffo954f1832014-10-11 18:27:30 +0300684 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200685 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300686 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200687 weston_log("failed to init output pixman state with "
688 "new mode\n");
689 return -1;
690 }
691 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +0000692 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300693 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200694 weston_log("failed to init output egl state with "
695 "new mode");
696 return -1;
697 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200698 }
699
Alex Wub7b8bda2012-04-17 17:20:48 +0800700 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800701}
702
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200703static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300704init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200705{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300706 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200707}
708
Pekka Paalanen7b36b422014-06-04 14:00:53 +0300709/**
Pekka Paalanenec272712014-06-05 11:22:25 +0300710 * Create a drm_plane for a hardware plane
711 *
712 * Creates one drm_plane structure for a hardware plane, and initialises its
713 * properties and formats.
714 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100715 * In the absence of universal plane support, where KMS does not explicitly
716 * expose the primary and cursor planes to userspace, this may also create
717 * an 'internal' plane for internal management.
718 *
Pekka Paalanenec272712014-06-05 11:22:25 +0300719 * This function does not add the plane to the list of usable planes in Weston
720 * itself; the caller is responsible for this.
721 *
722 * Call drm_plane_destroy to clean up the plane.
723 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100724 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +0300725 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +0100726 * @param kplane DRM plane to create, or NULL if creating internal plane
727 * @param output Output to create internal plane for, or NULL
728 * @param type Type to use when creating internal plane, or invalid
729 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +0300730 */
731static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100732drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
733 struct drm_output *output, enum wdrm_plane_type type,
734 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +0300735{
736 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100737 drmModeObjectProperties *props;
Marius Vladcdd6fa22019-08-29 20:42:00 +0300738 uint64_t *zpos_range_values;
Sergi Granellf4456222017-01-12 17:17:32 +0000739 uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100740
Daniel Stone2ba17f42015-05-19 20:02:41 +0100741 plane = zalloc(sizeof(*plane) +
Sergi Granellf4456222017-01-12 17:17:32 +0000742 (sizeof(plane->formats[0]) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +0300743 if (!plane) {
744 weston_log("%s: out of memory\n", __func__);
745 return NULL;
746 }
747
748 plane->backend = b;
Sergi Granellf4456222017-01-12 17:17:32 +0000749 plane->count_formats = num_formats;
Daniel Stonebc15f682016-11-14 16:57:01 +0000750 plane->state_cur = drm_plane_state_alloc(NULL, plane);
751 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +0300752
Daniel Stone2ba17f42015-05-19 20:02:41 +0100753 if (kplane) {
754 plane->possible_crtcs = kplane->possible_crtcs;
755 plane->plane_id = kplane->plane_id;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100756
757 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
758 DRM_MODE_OBJECT_PLANE);
759 if (!props) {
760 weston_log("couldn't get plane properties\n");
761 goto err;
762 }
763 drm_property_info_populate(b, plane_props, plane->props,
764 WDRM_PLANE__COUNT, props);
765 plane->type =
766 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
767 props,
768 WDRM_PLANE_TYPE__COUNT);
Sergi Granellf4456222017-01-12 17:17:32 +0000769
Marius Vladcdd6fa22019-08-29 20:42:00 +0300770 zpos_range_values =
Daniel Stone7fa97e62020-03-06 11:03:01 +0000771 drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
Marius Vladcdd6fa22019-08-29 20:42:00 +0300772 props);
773
774 if (zpos_range_values) {
775 plane->zpos_min = zpos_range_values[0];
776 plane->zpos_max = zpos_range_values[1];
777 } else {
778 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
779 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
780 }
781
Sergi Granellf4456222017-01-12 17:17:32 +0000782 if (drm_plane_populate_formats(plane, kplane, props) < 0) {
783 drmModeFreeObjectProperties(props);
784 goto err;
785 }
786
Daniel Stone2ba17f42015-05-19 20:02:41 +0100787 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100788 }
Daniel Stone2ba17f42015-05-19 20:02:41 +0100789 else {
790 plane->possible_crtcs = (1 << output->pipe);
791 plane->plane_id = 0;
792 plane->count_formats = 1;
Sergi Granellf4456222017-01-12 17:17:32 +0000793 plane->formats[0].format = format;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100794 plane->type = type;
Marius Vladcdd6fa22019-08-29 20:42:00 +0300795 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
796 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100797 }
798
799 if (plane->type == WDRM_PLANE_TYPE__COUNT)
800 goto err_props;
801
802 /* With universal planes, everything is a DRM plane; without
803 * universal planes, the only DRM planes are overlay planes.
804 * Everything else is a fake plane. */
805 if (b->universal_planes) {
806 assert(kplane);
807 } else {
808 if (kplane)
809 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
810 else
811 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
812 output);
813 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100814
Pekka Paalanenec272712014-06-05 11:22:25 +0300815 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +0100816 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +0300817
818 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100819
820err_props:
821 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
822err:
823 drm_plane_state_free(plane->state_cur, true);
824 free(plane);
825 return NULL;
826}
827
828/**
829 * Find, or create, a special-purpose plane
830 *
831 * Primary and cursor planes are a special case, in that before universal
832 * planes, they are driven by non-plane API calls. Without universal plane
833 * support, the only way to configure a primary plane is via drmModeSetCrtc,
834 * and the only way to configure a cursor plane is drmModeSetCursor2.
835 *
836 * Although they may actually be regular planes in the hardware, without
837 * universal plane support, these planes are not actually exposed to
838 * userspace in the regular plane list.
839 *
840 * However, for ease of internal tracking, we want to manage all planes
841 * through the same drm_plane structures. Therefore, when we are running
842 * without universal plane support, we create fake drm_plane structures
843 * to track these planes.
844 *
845 * @param b DRM backend
846 * @param output Output to use for plane
847 * @param type Type of plane
848 */
849static struct drm_plane *
850drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
851 enum wdrm_plane_type type)
852{
853 struct drm_plane *plane;
854
855 if (!b->universal_planes) {
856 uint32_t format;
857
858 switch (type) {
859 case WDRM_PLANE_TYPE_CURSOR:
Stefan Agner0bfebeb2019-07-08 00:30:44 +0200860 format = DRM_FORMAT_ARGB8888;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100861 break;
Daniel Stonee2e80132018-01-16 15:37:33 +0000862 case WDRM_PLANE_TYPE_PRIMARY:
863 /* We don't know what formats the primary plane supports
864 * before universal planes, so we just assume that the
865 * GBM format works; however, this isn't set until after
866 * the output is created. */
867 format = 0;
868 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100869 default:
870 assert(!"invalid type in drm_output_find_special_plane");
871 break;
872 }
873
874 return drm_plane_create(b, NULL, output, type, format);
875 }
876
877 wl_list_for_each(plane, &b->plane_list, link) {
878 struct drm_output *tmp;
879 bool found_elsewhere = false;
880
881 if (plane->type != type)
882 continue;
883 if (!drm_plane_is_available(plane, output))
884 continue;
885
886 /* On some platforms, primary/cursor planes can roam
887 * between different CRTCs, so make sure we don't claim the
888 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +0100889 wl_list_for_each(tmp, &b->compositor->output_list,
890 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +0000891 if (tmp->cursor_plane == plane ||
892 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +0100893 found_elsewhere = true;
894 break;
895 }
896 }
897
898 if (found_elsewhere)
899 continue;
900
901 plane->possible_crtcs = (1 << output->pipe);
902 return plane;
903 }
904
905 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +0300906}
907
908/**
909 * Destroy one DRM plane
910 *
911 * Destroy a DRM plane, removing it from screen and releasing its retained
912 * buffers in the process. The counterpart to drm_plane_create.
913 *
914 * @param plane Plane to deallocate (will be freed)
915 */
916static void
917drm_plane_destroy(struct drm_plane *plane)
918{
Daniel Stone2ba17f42015-05-19 20:02:41 +0100919 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
920 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
921 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +0000922 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100923 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +0300924 weston_plane_release(&plane->base);
925 wl_list_remove(&plane->link);
926 free(plane);
927}
928
929/**
930 * Initialise sprites (overlay planes)
931 *
932 * Walk the list of provided DRM planes, and add overlay planes.
933 *
934 * Call destroy_sprites to free these planes.
935 *
936 * @param b DRM compositor backend
937 */
938static void
939create_sprites(struct drm_backend *b)
940{
941 drmModePlaneRes *kplane_res;
942 drmModePlane *kplane;
943 struct drm_plane *drm_plane;
944 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +0300945 kplane_res = drmModeGetPlaneResources(b->drm.fd);
946 if (!kplane_res) {
947 weston_log("failed to get plane resources: %s\n",
948 strerror(errno));
949 return;
950 }
951
952 for (i = 0; i < kplane_res->count_planes; i++) {
953 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
954 if (!kplane)
955 continue;
956
Daniel Stone2ba17f42015-05-19 20:02:41 +0100957 drm_plane = drm_plane_create(b, kplane, NULL,
958 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +0300959 drmModeFreePlane(kplane);
960 if (!drm_plane)
961 continue;
962
Daniel Stone085d2b92015-05-21 00:00:57 +0100963 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
964 weston_compositor_stack_plane(b->compositor,
965 &drm_plane->base,
966 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +0300967 }
968
969 drmModeFreePlaneResources(kplane_res);
970}
971
972/**
973 * Clean up sprites (overlay planes)
974 *
975 * The counterpart to create_sprites.
976 *
977 * @param b DRM compositor backend
978 */
979static void
980destroy_sprites(struct drm_backend *b)
981{
982 struct drm_plane *plane, *next;
983
Daniel Stone085d2b92015-05-21 00:00:57 +0100984 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +0300985 drm_plane_destroy(plane);
986}
987
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -0300988/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200989static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +0300990drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200991{
992 long brightness, max_brightness, norm;
993
Pekka Paalanence724242017-09-04 12:21:24 +0300994 brightness = backlight_get_brightness(head->backlight);
995 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200996
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -0300997 /* convert it on a scale of 0 to 255 */
998 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200999
1000 return (uint32_t) norm;
1001}
1002
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001003/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001004static void
1005drm_set_backlight(struct weston_output *output_base, uint32_t value)
1006{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001007 struct drm_output *output = to_drm_output(output_base);
1008 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001009 long max_brightness, new_brightness;
1010
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001011 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001012 return;
1013
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001014 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1015 if (!head->backlight)
1016 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001017
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001018 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001019
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001020 /* get denormalized value */
1021 new_brightness = (value * max_brightness) / 255;
1022
1023 backlight_set_brightness(head->backlight, new_brightness);
1024 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001025}
1026
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001027static void
1028drm_output_init_backlight(struct drm_output *output)
1029{
1030 struct weston_head *base;
1031 struct drm_head *head;
1032
1033 output->base.set_backlight = NULL;
1034
1035 wl_list_for_each(base, &output->base.head_list, output_link) {
1036 head = to_drm_head(base);
1037
1038 if (head->backlight) {
1039 weston_log("Initialized backlight for head '%s', device %s\n",
1040 head->base.name, head->backlight->path);
1041
1042 if (!output->base.set_backlight) {
1043 output->base.set_backlight = drm_set_backlight;
1044 output->base.backlight_current =
1045 drm_get_backlight(head);
1046 }
1047 }
1048 }
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001049}
1050
Daniel Stonea08512f2016-11-08 17:46:10 +00001051/**
1052 * Power output on or off
1053 *
1054 * The DPMS/power level of an output is used to switch it on or off. This
1055 * is DRM's hook for doing so, which can called either as part of repaint,
1056 * or independently of the repaint loop.
1057 *
1058 * If we are called as part of repaint, we simply set the relevant bit in
1059 * state and return.
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001060 *
1061 * This function is never called on a virtual output.
Daniel Stonea08512f2016-11-08 17:46:10 +00001062 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001063static void
1064drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1065{
Armin Krezović545dba62016-08-05 15:54:18 +02001066 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00001067 struct drm_backend *b = to_drm_backend(output_base->compositor);
1068 struct drm_pending_state *pending_state = b->repaint_data;
1069 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01001070 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001071
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001072 assert(!output->virtual);
1073
Daniel Stonea08512f2016-11-08 17:46:10 +00001074 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001075 return;
1076
Daniel Stonea08512f2016-11-08 17:46:10 +00001077 /* If we're being called during the repaint loop, then this is
1078 * simple: discard any previously-generated state, and create a new
1079 * state where we disable everything. When we come to flush, this
1080 * will be applied.
1081 *
1082 * However, we need to be careful: we can be called whilst another
1083 * output is in its repaint cycle (pending_state exists), but our
1084 * output still has an incomplete state application outstanding.
1085 * In that case, we need to wait until that completes. */
1086 if (pending_state && !output->state_last) {
1087 /* The repaint loop already sets DPMS on; we don't need to
1088 * explicitly set it on here, as it will already happen
1089 * whilst applying the repaint state. */
1090 if (level == WESTON_DPMS_ON)
1091 return;
1092
1093 state = drm_pending_state_get_output(pending_state, output);
1094 if (state)
1095 drm_output_state_free(state);
1096 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01001097 return;
1098 }
1099
Daniel Stonea08512f2016-11-08 17:46:10 +00001100 /* As we throw everything away when disabling, just send us back through
1101 * a repaint cycle. */
1102 if (level == WESTON_DPMS_ON) {
1103 if (output->dpms_off_pending)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001104 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +00001105 weston_output_schedule_repaint(output_base);
1106 return;
1107 }
1108
1109 /* If we've already got a request in the pipeline, then we need to
1110 * park our DPMS request until that request has quiesced. */
1111 if (output->state_last) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001112 output->dpms_off_pending = true;
Daniel Stonea08512f2016-11-08 17:46:10 +00001113 return;
1114 }
1115
1116 pending_state = drm_pending_state_alloc(b);
1117 drm_output_get_disable_state(pending_state, output);
1118 ret = drm_pending_state_apply_sync(pending_state);
1119 if (ret != 0)
1120 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001121}
1122
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001123static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001124 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
1125 [DRM_MODE_CONNECTOR_VGA] = "VGA",
1126 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
1127 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
1128 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
1129 [DRM_MODE_CONNECTOR_Composite] = "Composite",
1130 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
1131 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
1132 [DRM_MODE_CONNECTOR_Component] = "Component",
1133 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
1134 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
1135 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
1136 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
1137 [DRM_MODE_CONNECTOR_TV] = "TV",
1138 [DRM_MODE_CONNECTOR_eDP] = "eDP",
1139 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
1140 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Stefan Agner30e283d2018-08-20 17:11:38 +02001141 [DRM_MODE_CONNECTOR_DPI] = "DPI",
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001142};
1143
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001144/** Create a name given a DRM connector
1145 *
1146 * \param con The DRM connector whose type and id form the name.
1147 * \return A newly allocate string, or NULL on error. Must be free()'d
1148 * after use.
1149 *
1150 * The name does not identify the DRM display device.
1151 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001152static char *
1153make_connector_name(const drmModeConnector *con)
1154{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001155 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001156 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001157 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001158
1159 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1160 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001161
1162 if (!type_name)
1163 type_name = "UNNAMED";
1164
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001165 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
1166 if (ret < 0)
1167 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001168
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001169 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001170}
1171
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001172static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001173drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001174{
Hardeningff39efa2013-09-18 23:56:35 +02001175 int w = output->base.current_mode->width;
1176 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001177 uint32_t format = output->gbm_format;
1178 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001179 unsigned int i;
Pekka Paalanendee412d2018-04-23 11:44:58 +02001180 uint32_t flags = 0;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001181
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001182 switch (format) {
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001183 case DRM_FORMAT_XRGB8888:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001184 pixman_format = PIXMAN_x8r8g8b8;
1185 break;
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001186 case DRM_FORMAT_RGB565:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001187 pixman_format = PIXMAN_r5g6b5;
1188 break;
1189 default:
1190 weston_log("Unsupported pixman format 0x%x\n", format);
1191 return -1;
1192 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001193
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001194 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001195 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001196 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001197 if (!output->dumb[i])
1198 goto err;
1199
1200 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001201 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001202 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00001203 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001204 if (!output->image[i])
1205 goto err;
1206 }
1207
Pekka Paalanendee412d2018-04-23 11:44:58 +02001208 if (b->use_pixman_shadow)
1209 flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
1210
1211 if (pixman_renderer_output_create(&output->base, flags) < 0)
1212 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05301213
Pekka Paalanendee412d2018-04-23 11:44:58 +02001214 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
1215 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001216
1217 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001218 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001219
1220 return 0;
1221
1222err:
1223 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1224 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01001225 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001226 if (output->image[i])
1227 pixman_image_unref(output->image[i]);
1228
1229 output->dumb[i] = NULL;
1230 output->image[i] = NULL;
1231 }
1232
1233 return -1;
1234}
1235
1236static void
1237drm_output_fini_pixman(struct drm_output *output)
1238{
Daniel Stonee2e80132018-01-16 15:37:33 +00001239 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001240 unsigned int i;
1241
Daniel Stonee2e80132018-01-16 15:37:33 +00001242 /* Destroying the Pixman surface will destroy all our buffers,
1243 * regardless of refcount. Ensure we destroy them here. */
1244 if (!b->shutting_down &&
1245 output->scanout_plane->state_cur->fb &&
1246 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
1247 drm_plane_state_free(output->scanout_plane->state_cur, true);
1248 output->scanout_plane->state_cur =
1249 drm_plane_state_alloc(NULL, output->scanout_plane);
1250 output->scanout_plane->state_cur->complete = true;
1251 }
1252
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001253 pixman_renderer_output_destroy(&output->base);
1254 pixman_region32_fini(&output->previous_damage);
1255
1256 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001257 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001258 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001259 output->dumb[i] = NULL;
1260 output->image[i] = NULL;
1261 }
1262}
1263
Richard Hughes2b2092a2013-04-24 14:58:02 +01001264static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001265setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01001266 struct weston_output *output,
1267 const char *s)
1268{
1269 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05001270 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001271 struct udev_seat *seat;
1272
Giulio Camuffo954f1832014-10-11 18:27:30 +03001273 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05001274 if (!seat)
1275 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001276
Derek Foreman0720ea32015-07-15 13:00:35 -05001277 seat->base.output = output;
1278
Derek Foreman1281a362015-07-31 16:55:32 -05001279 pointer = weston_seat_get_pointer(&seat->base);
1280 if (pointer)
1281 weston_pointer_clamp(pointer,
1282 &pointer->x,
1283 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001284 }
1285}
1286
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001287static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03001288drm_output_attach_head(struct weston_output *output_base,
1289 struct weston_head *head_base)
1290{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001291 struct drm_backend *b = to_drm_backend(output_base->compositor);
1292
Pekka Paalanenc112f002017-08-28 16:27:20 +03001293 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
1294 return -1;
1295
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001296 if (!output_base->enabled)
1297 return 0;
1298
1299 /* XXX: ensure the configuration will work.
1300 * This is actually impossible without major infrastructure
1301 * work. */
1302
1303 /* Need to go through modeset to add connectors. */
1304 /* XXX: Ideally we'd do this per-output, not globally. */
1305 /* XXX: Doing it globally, what guarantees another output's update
1306 * will not clear the flag before this output is updated?
1307 */
1308 b->state_invalid = true;
1309
1310 weston_output_schedule_repaint(output_base);
1311
Pekka Paalanenc112f002017-08-28 16:27:20 +03001312 return 0;
1313}
1314
Pekka Paalanen7f853792017-11-29 14:33:33 +02001315static void
1316drm_output_detach_head(struct weston_output *output_base,
1317 struct weston_head *head_base)
1318{
1319 struct drm_backend *b = to_drm_backend(output_base->compositor);
1320
1321 if (!output_base->enabled)
1322 return;
1323
1324 /* Need to go through modeset to drop connectors that should no longer
1325 * be driven. */
1326 /* XXX: Ideally we'd do this per-output, not globally. */
1327 b->state_invalid = true;
1328
1329 weston_output_schedule_repaint(output_base);
1330}
1331
Stefan Agner3654c672019-07-09 00:50:30 +02001332int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001333parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001334{
Pekka Paalanen62a94362018-09-26 14:33:36 +03001335 const struct pixel_format_info *pinfo;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001336
Pekka Paalanen62a94362018-09-26 14:33:36 +03001337 if (s == NULL) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001338 *gbm_format = default_value;
Pekka Paalanen62a94362018-09-26 14:33:36 +03001339
1340 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001341 }
1342
Pekka Paalanen62a94362018-09-26 14:33:36 +03001343 pinfo = pixel_format_get_info_by_drm_name(s);
1344 if (!pinfo) {
1345 weston_log("fatal: unrecognized pixel format: %s\n", s);
1346
1347 return -1;
1348 }
1349
1350 /* GBM formats and DRM formats are identical. */
1351 *gbm_format = pinfo->format;
1352
1353 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001354}
1355
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001356static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001357drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001358{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001359 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001360 drmModeEncoder *encoder;
1361 drmModeCrtc *crtc;
1362
1363 /* Get the current mode on the crtc that's currently driving
1364 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001365 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001366 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001367 head->inherited_crtc_id = encoder->crtc_id;
1368
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001369 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
1370 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001371
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001372 if (crtc == NULL)
1373 return -1;
1374 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02001375 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001376 drmModeFreeCrtc(crtc);
1377 }
1378
1379 return 0;
1380}
1381
Armin Krezović08368132016-09-30 14:11:05 +02001382static void
1383drm_output_set_gbm_format(struct weston_output *base,
1384 const char *gbm_format)
1385{
1386 struct drm_output *output = to_drm_output(base);
1387 struct drm_backend *b = to_drm_backend(base->compositor);
1388
1389 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
1390 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00001391
1392 /* Without universal planes, we can't discover which formats are
1393 * supported by the primary plane; we just hope that the GBM format
1394 * works. */
1395 if (!b->universal_planes)
Sergi Granellf4456222017-01-12 17:17:32 +00001396 output->scanout_plane->formats[0].format = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02001397}
1398
1399static void
1400drm_output_set_seat(struct weston_output *base,
1401 const char *seat)
1402{
1403 struct drm_output *output = to_drm_output(base);
1404 struct drm_backend *b = to_drm_backend(base->compositor);
1405
1406 setup_output_seat_constraint(b, &output->base,
1407 seat ? seat : "");
1408}
1409
1410static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001411drm_output_init_gamma_size(struct drm_output *output)
1412{
1413 struct drm_backend *backend = to_drm_backend(output->base.compositor);
1414 drmModeCrtc *crtc;
1415
1416 assert(output->base.compositor);
1417 assert(output->crtc_id != 0);
1418 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
1419 if (!crtc)
1420 return -1;
1421
1422 output->base.gamma_size = crtc->gamma_size;
1423
1424 drmModeFreeCrtc(crtc);
1425
1426 return 0;
1427}
1428
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001429static uint32_t
1430drm_head_get_possible_crtcs_mask(struct drm_head *head)
1431{
1432 uint32_t possible_crtcs = 0;
1433 drmModeEncoder *encoder;
1434 int i;
1435
1436 for (i = 0; i < head->connector->count_encoders; i++) {
1437 encoder = drmModeGetEncoder(head->backend->drm.fd,
1438 head->connector->encoders[i]);
1439 if (!encoder)
1440 continue;
1441
1442 possible_crtcs |= encoder->possible_crtcs;
1443 drmModeFreeEncoder(encoder);
1444 }
1445
1446 return possible_crtcs;
1447}
1448
1449static int
1450drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
1451{
1452 int i;
1453
1454 for (i = 0; i < resources->count_crtcs; i++) {
1455 if (resources->crtcs[i] == crtc_id)
1456 return i;
1457 }
1458
1459 assert(0 && "unknown crtc id");
1460 return -1;
1461}
1462
1463/** Pick a CRTC that might be able to drive all attached connectors
1464 *
1465 * @param output The output whose attached heads to include.
1466 * @param resources The DRM KMS resources.
1467 * @return CRTC index, or -1 on failure or not found.
1468 */
1469static int
1470drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
1471{
1472 struct drm_backend *backend;
1473 struct weston_head *base;
1474 struct drm_head *head;
1475 uint32_t possible_crtcs = 0xffffffff;
1476 int existing_crtc[32];
1477 unsigned j, n = 0;
1478 uint32_t crtc_id;
1479 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001480 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001481 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001482 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001483
1484 backend = to_drm_backend(output->base.compositor);
1485
1486 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
1487 * because it is more often set wrong than not in the kernel. */
1488
1489 /* Accumulate a mask of possible crtcs and find existing routings. */
1490 wl_list_for_each(base, &output->base.head_list, output_link) {
1491 head = to_drm_head(base);
1492
1493 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
1494
1495 crtc_id = head->inherited_crtc_id;
1496 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
1497 existing_crtc[n++] = drm_crtc_get_index(resources,
1498 crtc_id);
1499 }
1500
1501 /* Find a crtc that could drive each connector individually at least,
1502 * and prefer existing routings. */
1503 for (i = 0; i < resources->count_crtcs; i++) {
1504 crtc_id = resources->crtcs[i];
1505
1506 /* Could the crtc not drive each connector? */
1507 if (!(possible_crtcs & (1 << i)))
1508 continue;
1509
1510 /* Is the crtc already in use? */
1511 if (drm_output_find_by_crtc(backend, crtc_id))
1512 continue;
1513
1514 /* Try to preserve the existing CRTC -> connector routing;
1515 * it makes initialisation faster, and also since we have a
1516 * very dumb picking algorithm, may preserve a better
1517 * choice. */
1518 for (j = 0; j < n; j++) {
1519 if (existing_crtc[j] == i)
1520 return i;
1521 }
1522
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001523 /* Check if any other head had existing routing to this CRTC.
1524 * If they did, this is not the best CRTC as it might be needed
1525 * for another output we haven't enabled yet. */
1526 match = false;
1527 wl_list_for_each(base, &backend->compositor->head_list,
1528 compositor_link) {
1529 head = to_drm_head(base);
1530
1531 if (head->base.output == &output->base)
1532 continue;
1533
1534 if (weston_head_is_enabled(&head->base))
1535 continue;
1536
1537 if (head->inherited_crtc_id == crtc_id) {
1538 match = true;
1539 break;
1540 }
1541 }
1542 if (!match)
1543 best_crtc_index = i;
1544
1545 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001546 }
1547
1548 if (best_crtc_index != -1)
1549 return best_crtc_index;
1550
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001551 if (fallback_crtc_index != -1)
1552 return fallback_crtc_index;
1553
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001554 /* Likely possible_crtcs was empty due to asking for clones,
1555 * but since the DRM documentation says the kernel lies, let's
1556 * pick one crtc anyway. Trial and error is the only way to
1557 * be sure if something doesn't work. */
1558
1559 /* First pick any existing assignment. */
1560 for (j = 0; j < n; j++) {
1561 crtc_id = resources->crtcs[existing_crtc[j]];
1562 if (!drm_output_find_by_crtc(backend, crtc_id))
1563 return existing_crtc[j];
1564 }
1565
1566 /* Otherwise pick any available crtc. */
1567 for (i = 0; i < resources->count_crtcs; i++) {
1568 crtc_id = resources->crtcs[i];
1569
1570 if (!drm_output_find_by_crtc(backend, crtc_id))
1571 return i;
1572 }
1573
1574 return -1;
1575}
1576
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001577/** Allocate a CRTC for the output
1578 *
1579 * @param output The output with no allocated CRTC.
1580 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001581 * @return 0 on success, -1 on failure.
1582 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001583 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001584 * for the output, and loads the CRTC properties.
1585 *
1586 * Populates the cursor and scanout planes.
1587 *
1588 * On failure, the output remains without a CRTC.
1589 */
1590static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001591drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001592{
1593 struct drm_backend *b = to_drm_backend(output->base.compositor);
1594 drmModeObjectPropertiesPtr props;
1595 int i;
1596
1597 assert(output->crtc_id == 0);
1598
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001599 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001600 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001601 weston_log("Output '%s': No available CRTCs.\n",
1602 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001603 return -1;
1604 }
1605
1606 output->crtc_id = resources->crtcs[i];
1607 output->pipe = i;
1608
1609 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
1610 DRM_MODE_OBJECT_CRTC);
1611 if (!props) {
1612 weston_log("failed to get CRTC properties\n");
1613 goto err_crtc;
1614 }
1615 drm_property_info_populate(b, crtc_props, output->props_crtc,
1616 WDRM_CRTC__COUNT, props);
1617 drmModeFreeObjectProperties(props);
1618
1619 output->scanout_plane =
1620 drm_output_find_special_plane(b, output,
1621 WDRM_PLANE_TYPE_PRIMARY);
1622 if (!output->scanout_plane) {
1623 weston_log("Failed to find primary plane for output %s\n",
1624 output->base.name);
1625 goto err_crtc;
1626 }
1627
1628 /* Failing to find a cursor plane is not fatal, as we'll fall back
1629 * to software cursor. */
1630 output->cursor_plane =
1631 drm_output_find_special_plane(b, output,
1632 WDRM_PLANE_TYPE_CURSOR);
1633
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001634 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
1635
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001636 return 0;
1637
1638err_crtc:
1639 output->crtc_id = 0;
1640 output->pipe = 0;
1641
1642 return -1;
1643}
1644
1645/** Free the CRTC from the output
1646 *
1647 * @param output The output whose CRTC to deallocate.
1648 *
1649 * The CRTC reserved for the given output becomes free to use again.
1650 */
1651static void
1652drm_output_fini_crtc(struct drm_output *output)
1653{
1654 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001655 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001656
1657 if (!b->universal_planes && !b->shutting_down) {
1658 /* With universal planes, the 'special' planes are allocated at
1659 * startup, freed at shutdown, and live on the plane list in
1660 * between. We want the planes to continue to exist and be freed
1661 * up for other outputs.
1662 *
1663 * Without universal planes, our special planes are
1664 * pseudo-planes allocated at output creation, freed at output
1665 * destruction, and not usable by other outputs.
1666 *
1667 * On the other hand, if the compositor is already shutting down,
1668 * the plane has already been destroyed.
1669 */
1670 if (output->cursor_plane)
1671 drm_plane_destroy(output->cursor_plane);
1672 if (output->scanout_plane)
1673 drm_plane_destroy(output->scanout_plane);
1674 }
1675
1676 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001677
1678 assert(output->crtc_id != 0);
1679
1680 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
1681 *unused = output->crtc_id;
1682
1683 /* Force resetting unused CRTCs */
1684 b->state_invalid = true;
1685
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001686 output->crtc_id = 0;
1687 output->cursor_plane = NULL;
1688 output->scanout_plane = NULL;
1689}
1690
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001691static int
Armin Krezović08368132016-09-30 14:11:05 +02001692drm_output_enable(struct weston_output *base)
1693{
1694 struct drm_output *output = to_drm_output(base);
1695 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001696 drmModeRes *resources;
1697 int ret;
1698
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001699 assert(!output->virtual);
1700
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001701 resources = drmModeGetResources(b->drm.fd);
1702 if (!resources) {
1703 weston_log("drmModeGetResources failed\n");
1704 return -1;
1705 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001706 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001707 drmModeFreeResources(resources);
1708 if (ret < 0)
1709 return -1;
1710
1711 if (drm_output_init_gamma_size(output) < 0)
1712 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02001713
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001714 if (b->pageflip_timeout)
1715 drm_output_pageflip_timer_create(output);
1716
Giulio Camuffo954f1832014-10-11 18:27:30 +03001717 if (b->use_pixman) {
1718 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001719 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00001720 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001721 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03001722 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001723 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00001724 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001725 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001726
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001727 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001728
Jonas Ådahle5a12252013-04-05 23:07:11 +02001729 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001730 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001731 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001732 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001733 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01001734 output->base.set_gamma = drm_output_set_gamma;
1735
Daniel Stone2ba17f42015-05-19 20:02:41 +01001736 if (output->cursor_plane)
1737 weston_compositor_stack_plane(b->compositor,
1738 &output->cursor_plane->base,
1739 NULL);
1740 else
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001741 b->cursors_are_broken = true;
Daniel Stone2ba17f42015-05-19 20:02:41 +01001742
Daniel Stonee2e80132018-01-16 15:37:33 +00001743 weston_compositor_stack_plane(b->compositor,
1744 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001745 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001746
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001747 weston_log("Output %s (crtc %d) video modes:\n",
1748 output->base.name, output->crtc_id);
1749 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001750
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001751 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001752
Daniel Stone02cf4662017-03-03 16:19:39 +00001753err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001754 drm_output_fini_crtc(output);
1755
David Herrmann0f0d54e2011-12-08 17:05:45 +01001756 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001757}
1758
Jesse Barnes58ef3792012-02-23 09:45:49 -05001759static void
Armin Krezović08368132016-09-30 14:11:05 +02001760drm_output_deinit(struct weston_output *base)
1761{
1762 struct drm_output *output = to_drm_output(base);
1763 struct drm_backend *b = to_drm_backend(base->compositor);
1764
Daniel Stone3e661f72016-11-04 17:24:06 +00001765 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02001766 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00001767 else
1768 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02001769
Daniel Stone2ba17f42015-05-19 20:02:41 +01001770 /* Since our planes are no longer in use anywhere, remove their base
1771 * weston_plane's link from the plane stacking list, unless we're
1772 * shutting down, in which case the plane has already been
1773 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00001774 if (!b->shutting_down) {
1775 wl_list_remove(&output->scanout_plane->base.link);
1776 wl_list_init(&output->scanout_plane->base.link);
1777
1778 if (output->cursor_plane) {
1779 wl_list_remove(&output->cursor_plane->base.link);
1780 wl_list_init(&output->cursor_plane->base.link);
1781 /* Turn off hardware cursor */
1782 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
1783 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01001784 }
Daniel Stone087ddf02017-02-14 17:51:30 +00001785
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001786 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02001787}
1788
1789static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03001790drm_head_destroy(struct drm_head *head);
1791
1792static void
Armin Krezović08368132016-09-30 14:11:05 +02001793drm_output_destroy(struct weston_output *base)
1794{
1795 struct drm_output *output = to_drm_output(base);
1796 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02001797
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001798 assert(!output->virtual);
1799
Daniel Stone31838bf2019-06-17 11:23:25 +01001800 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001801 output->destroy_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001802 weston_log("destroy output while page flip pending\n");
1803 return;
1804 }
1805
1806 if (output->base.enabled)
1807 drm_output_deinit(&output->base);
1808
Pekka Paalanen383b3af2017-09-11 14:40:48 +03001809 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02001810
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001811 if (output->pageflip_timer)
1812 wl_event_source_remove(output->pageflip_timer);
1813
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03001814 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02001815
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001816 assert(!output->state_last);
1817 drm_output_state_free(output->state_cur);
1818
Armin Krezović08368132016-09-30 14:11:05 +02001819 free(output);
1820}
1821
1822static int
1823drm_output_disable(struct weston_output *base)
1824{
1825 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02001826
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001827 assert(!output->virtual);
1828
Daniel Stone31838bf2019-06-17 11:23:25 +01001829 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001830 output->disable_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001831 return -1;
1832 }
1833
Daniel Stonea08512f2016-11-08 17:46:10 +00001834 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00001835
Armin Krezović08368132016-09-30 14:11:05 +02001836 if (output->base.enabled)
1837 drm_output_deinit(&output->base);
1838
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001839 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02001840
Armin Krezović08368132016-09-30 14:11:05 +02001841 return 0;
1842}
1843
1844/**
Daniel Stone087ddf02017-02-14 17:51:30 +00001845 * Update the list of unused connectors and CRTCs
1846 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03001847 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00001848 *
1849 * @param b Weston backend structure
1850 * @param resources DRM resources for this device
1851 */
1852static void
1853drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
1854{
1855 int i;
1856
Daniel Stone087ddf02017-02-14 17:51:30 +00001857 wl_array_release(&b->unused_crtcs);
1858 wl_array_init(&b->unused_crtcs);
1859
1860 for (i = 0; i < resources->count_crtcs; i++) {
1861 struct drm_output *output;
1862 uint32_t *crtc_id;
1863
1864 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
1865 if (output && output->base.enabled)
1866 continue;
1867
1868 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
1869 *crtc_id = resources->crtcs[i];
1870 }
1871}
1872
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301873/*
1874 * This function converts the protection status from drm values to
1875 * weston_hdcp_protection status. The drm values as read from the connector
1876 * properties "Content Protection" and "HDCP Content Type" need to be converted
1877 * to appropriate weston values, that can be sent to a client application.
1878 */
1879static int
1880get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
1881 enum wdrm_hdcp_content_type type,
1882 enum weston_hdcp_protection *weston_protection)
1883
1884{
1885 if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
1886 return -1;
1887 if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
1888 protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
1889 *weston_protection = WESTON_HDCP_DISABLE;
1890 return 0;
1891 }
1892 if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
1893 return -1;
1894 if (type == WDRM_HDCP_CONTENT_TYPE0) {
1895 *weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
1896 return 0;
1897 }
1898 if (type == WDRM_HDCP_CONTENT_TYPE1) {
1899 *weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
1900 return 0;
1901 }
1902 return -1;
1903}
1904
1905/**
1906 * Get current content-protection status for a given head.
1907 *
1908 * @param head drm_head, whose protection is to be retrieved
1909 * @param props drm property object of the connector, related to the head
1910 * @return protection status in case of success, -1 otherwise
1911 */
1912static enum weston_hdcp_protection
1913drm_head_get_current_protection(struct drm_head *head,
1914 drmModeObjectProperties *props)
1915{
1916 struct drm_property_info *info;
1917 enum wdrm_content_protection_state protection;
1918 enum wdrm_hdcp_content_type type;
1919 enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
1920
1921 info = &head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION];
1922 protection = drm_property_get_value(info, props,
1923 WDRM_CONTENT_PROTECTION__COUNT);
1924
1925 if (protection == WDRM_CONTENT_PROTECTION__COUNT)
1926 return WESTON_HDCP_DISABLE;
1927
1928 info = &head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
1929 type = drm_property_get_value(info, props,
1930 WDRM_HDCP_CONTENT_TYPE__COUNT);
1931
1932 /*
1933 * In case of platforms supporting HDCP1.4, only property
1934 * 'Content Protection' is exposed and not the 'HDCP Content Type'
1935 * for such cases HDCP Type 0 should be considered as the content-type.
1936 */
1937
1938 if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
1939 type = WDRM_HDCP_CONTENT_TYPE0;
1940
1941 if (get_weston_protection_from_drm(protection, type,
1942 &weston_hdcp) == -1) {
1943 weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
1944 protection, type, head->base.name,
1945 head->connector_id);
1946 return WESTON_HDCP_DISABLE;
1947 }
1948
1949 return weston_hdcp;
1950}
1951
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001952/** Replace connector data and monitor information
1953 *
1954 * @param head The head to update.
1955 * @param connector The connector data to be owned by the head, must match
1956 * the head's connector ID.
1957 * @return 0 on success, -1 on failure.
1958 *
1959 * Takes ownership of @c connector on success, not on failure.
1960 *
1961 * May schedule a heads changed call.
1962 */
1963static int
1964drm_head_assign_connector_info(struct drm_head *head,
1965 drmModeConnector *connector)
1966{
1967 drmModeObjectProperties *props;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001968
1969 assert(connector);
1970 assert(head->connector_id == connector->connector_id);
1971
1972 props = drmModeObjectGetProperties(head->backend->drm.fd,
1973 head->connector_id,
1974 DRM_MODE_OBJECT_CONNECTOR);
1975 if (!props) {
1976 weston_log("Error: failed to get connector '%s' properties\n",
1977 head->base.name);
1978 return -1;
1979 }
1980
1981 if (head->connector)
1982 drmModeFreeConnector(head->connector);
1983 head->connector = connector;
1984
1985 drm_property_info_populate(head->backend, connector_props,
1986 head->props_conn,
1987 WDRM_CONNECTOR__COUNT, props);
Daniel Stone3448cfc2019-06-26 22:56:39 +01001988 update_head_from_connector(head, props);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301989
1990 weston_head_set_content_protection_status(&head->base,
1991 drm_head_get_current_protection(head, props));
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001992 drmModeFreeObjectProperties(props);
1993
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001994 return 0;
1995}
1996
Pekka Paalanen456dc732017-11-09 15:10:11 +02001997static void
1998drm_head_log_info(struct drm_head *head, const char *msg)
1999{
2000 if (head->base.connected) {
2001 weston_log("DRM: head '%s' %s, connector %d is connected, "
2002 "EDID make '%s', model '%s', serial '%s'\n",
2003 head->base.name, msg, head->connector_id,
2004 head->base.make, head->base.model,
2005 head->base.serial_number ?: "");
2006 } else {
2007 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
2008 head->base.name, msg, head->connector_id);
2009 }
2010}
2011
Pekka Paalanend2e62422017-09-08 15:48:07 +03002012/** Update connector and monitor information
2013 *
2014 * @param head The head to update.
2015 *
2016 * Re-reads the DRM property lists for the connector and updates monitor
2017 * information and connection status. This may schedule a heads changed call
2018 * to the user.
2019 */
2020static void
2021drm_head_update_info(struct drm_head *head)
2022{
2023 drmModeConnector *connector;
2024
2025 connector = drmModeGetConnector(head->backend->drm.fd,
2026 head->connector_id);
2027 if (!connector) {
2028 weston_log("DRM: getting connector info for '%s' failed.\n",
2029 head->base.name);
2030 return;
2031 }
2032
2033 if (drm_head_assign_connector_info(head, connector) < 0)
2034 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002035
2036 if (head->base.device_changed)
2037 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03002038}
2039
Daniel Stone087ddf02017-02-14 17:51:30 +00002040/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03002041 * Create a Weston head for a connector
2042 *
2043 * Given a DRM connector, create a matching drm_head structure and add it
2044 * to Weston's head list.
2045 *
Marius Vlada2dace22019-06-12 16:05:44 +03002046 * @param backend Weston backend structure
Pekka Paalanenc112f002017-08-28 16:27:20 +03002047 * @param connector_id DRM connector ID for the head
2048 * @param drm_device udev device pointer
2049 * @returns The new head, or NULL on failure.
2050 */
2051static struct drm_head *
2052drm_head_create(struct drm_backend *backend, uint32_t connector_id,
2053 struct udev_device *drm_device)
2054{
2055 struct drm_head *head;
2056 drmModeConnector *connector;
2057 char *name;
2058
2059 head = zalloc(sizeof *head);
2060 if (!head)
2061 return NULL;
2062
2063 connector = drmModeGetConnector(backend->drm.fd, connector_id);
2064 if (!connector)
2065 goto err_alloc;
2066
2067 name = make_connector_name(connector);
2068 if (!name)
2069 goto err_alloc;
2070
2071 weston_head_init(&head->base, name);
2072 free(name);
2073
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002074 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002075 head->backend = backend;
2076
Pekka Paalanence724242017-09-04 12:21:24 +03002077 head->backlight = backlight_init(drm_device, connector->connector_type);
2078
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002079 if (drm_head_assign_connector_info(head, connector) < 0)
2080 goto err_init;
2081
2082 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
2083 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
2084 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002085
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02002086 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002087 weston_log("Failed to retrieve current mode from connector %d.\n",
2088 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02002089 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002090 }
2091
Pekka Paalanenc112f002017-08-28 16:27:20 +03002092 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002093 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03002094
2095 return head;
2096
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002097err_init:
2098 weston_head_release(&head->base);
2099
Pekka Paalanenc112f002017-08-28 16:27:20 +03002100err_alloc:
2101 if (connector)
2102 drmModeFreeConnector(connector);
2103
2104 free(head);
2105
2106 return NULL;
2107}
2108
2109static void
2110drm_head_destroy(struct drm_head *head)
2111{
2112 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03002113
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002114 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
2115 drmModeFreeConnector(head->connector);
2116
Pekka Paalanence724242017-09-04 12:21:24 +03002117 if (head->backlight)
2118 backlight_destroy(head->backlight);
2119
Pekka Paalanenc112f002017-08-28 16:27:20 +03002120 free(head);
2121}
2122
2123/**
Armin Krezović08368132016-09-30 14:11:05 +02002124 * Create a Weston output structure
2125 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002126 * Create an "empty" drm_output. This is the implementation of
2127 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02002128 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002129 * Creating an output is usually followed by drm_output_attach_head()
2130 * and drm_output_enable() to make use of it.
2131 *
2132 * @param compositor The compositor instance.
2133 * @param name Name for the new output.
2134 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02002135 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03002136static struct weston_output *
2137drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02002138{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002139 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02002140 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02002141
Armin Krezović08368132016-09-30 14:11:05 +02002142 output = zalloc(sizeof *output);
2143 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002144 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02002145
Daniel Stone64dbbee2018-07-20 19:00:06 +01002146 output->backend = b;
Stefan Agnerccf24072019-07-09 22:02:00 +02002147#ifdef BUILD_DRM_GBM
Tomohito Esaki718a40b2018-01-31 17:50:15 +09002148 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Stefan Agnerccf24072019-07-09 22:02:00 +02002149#endif
Daniel Stone64dbbee2018-07-20 19:00:06 +01002150
Pekka Paalanend2e62422017-09-08 15:48:07 +03002151 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002152
Armin Krezović08368132016-09-30 14:11:05 +02002153 output->base.enable = drm_output_enable;
2154 output->base.destroy = drm_output_destroy;
2155 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002156 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02002157 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02002158
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002159 output->destroy_pending = false;
2160 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02002161
Pekka Paalanen01f60212017-03-24 15:39:24 +02002162 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03002163
Armin Krezović08368132016-09-30 14:11:05 +02002164 weston_compositor_add_pending_output(&output->base, b->compositor);
2165
Pekka Paalanend2e62422017-09-08 15:48:07 +03002166 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02002167}
2168
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002169static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03002170drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002171{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002172 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002173 drmModeRes *resources;
2174 int i;
2175
Giulio Camuffo954f1832014-10-11 18:27:30 +03002176 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002177 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002178 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002179 return -1;
2180 }
2181
Giulio Camuffo954f1832014-10-11 18:27:30 +03002182 b->min_width = resources->min_width;
2183 b->max_width = resources->max_width;
2184 b->min_height = resources->min_height;
2185 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002186
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002187 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002188 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00002189
Pekka Paalanend2e62422017-09-08 15:48:07 +03002190 head = drm_head_create(b, connector_id, drm_device);
2191 if (!head) {
2192 weston_log("DRM: failed to create head for connector %d.\n",
2193 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002194 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002195 }
2196
Daniel Stone087ddf02017-02-14 17:51:30 +00002197 drm_backend_update_unused_outputs(b, resources);
2198
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002199 drmModeFreeResources(resources);
2200
2201 return 0;
2202}
2203
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002204static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03002205drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002206{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002207 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002208 struct weston_head *base, *next;
2209 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002210 int i;
2211
Giulio Camuffo954f1832014-10-11 18:27:30 +03002212 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002213 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002214 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002215 return;
2216 }
2217
Pekka Paalanend2e62422017-09-08 15:48:07 +03002218 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002219 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00002220 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02002221
Pekka Paalanend2e62422017-09-08 15:48:07 +03002222 head = drm_head_find_by_connector(b, connector_id);
2223 if (head) {
2224 drm_head_update_info(head);
2225 } else {
2226 head = drm_head_create(b, connector_id, drm_device);
2227 if (!head)
2228 weston_log("DRM: failed to create head for hot-added connector %d.\n",
2229 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002230 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002231 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002232
Pekka Paalanend2e62422017-09-08 15:48:07 +03002233 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03002234 wl_list_for_each_safe(base, next,
2235 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002236 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002237
Pekka Paalanena0a37462017-08-31 15:41:57 +03002238 head = to_drm_head(base);
2239
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002240 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002241 if (resources->connectors[i] == head->connector_id) {
2242 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002243 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002244 }
2245 }
Armin Krezović08368132016-09-30 14:11:05 +02002246
Pekka Paalanend2e62422017-09-08 15:48:07 +03002247 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002248 continue;
2249
Pekka Paalanend2e62422017-09-08 15:48:07 +03002250 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
2251 head->base.name, head->connector_id);
2252 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002253 }
2254
Daniel Stone087ddf02017-02-14 17:51:30 +00002255 drm_backend_update_unused_outputs(b, resources);
2256
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002257 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002258}
2259
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302260static enum wdrm_connector_property
2261drm_head_find_property_by_id(struct drm_head *head, uint32_t property_id)
2262{
2263 int i;
2264 enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
2265
2266 if (!head || !property_id)
2267 return WDRM_CONNECTOR__COUNT;
2268
2269 for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
2270 if (head->props_conn[i].prop_id == property_id) {
2271 prop = (enum wdrm_connector_property) i;
2272 break;
2273 }
2274 return prop;
2275}
2276
2277static void
2278drm_backend_update_conn_props(struct drm_backend *b,
2279 uint32_t connector_id,
2280 uint32_t property_id)
2281{
2282 struct drm_head *head;
2283 enum wdrm_connector_property conn_prop;
2284 drmModeObjectProperties *props;
2285
2286 head = drm_head_find_by_connector(b, connector_id);
2287 if (!head) {
2288 weston_log("DRM: failed to find head for connector id: %d.\n",
2289 connector_id);
2290 return;
2291 }
2292
2293 conn_prop = drm_head_find_property_by_id(head, property_id);
2294 if (conn_prop >= WDRM_CONNECTOR__COUNT)
2295 return;
2296
2297 props = drmModeObjectGetProperties(b->drm.fd,
2298 connector_id,
2299 DRM_MODE_OBJECT_CONNECTOR);
2300 if (!props) {
2301 weston_log("Error: failed to get connector '%s' properties\n",
2302 head->base.name);
2303 return;
2304 }
2305 if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
2306 weston_head_set_content_protection_status(&head->base,
2307 drm_head_get_current_protection(head, props));
2308 }
2309 drmModeFreeObjectProperties(props);
2310}
2311
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002312static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002313udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002314{
David Herrmannd7488c22012-03-11 20:05:21 +01002315 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002316 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002317
2318 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002319 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002320 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002321
David Herrmann6ac52db2012-03-11 20:05:22 +01002322 val = udev_device_get_property_value(device, "HOTPLUG");
2323 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002324 return 0;
2325
David Herrmann6ac52db2012-03-11 20:05:22 +01002326 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002327}
2328
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002329static int
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302330udev_event_is_conn_prop_change(struct drm_backend *b,
2331 struct udev_device *device,
2332 uint32_t *connector_id,
2333 uint32_t *property_id)
2334
2335{
2336 const char *val;
2337 int id;
2338
2339 val = udev_device_get_property_value(device, "CONNECTOR");
2340 if (!val || !safe_strtoint(val, &id))
2341 return 0;
2342 else
2343 *connector_id = id;
2344
2345 val = udev_device_get_property_value(device, "PROPERTY");
2346 if (!val || !safe_strtoint(val, &id))
2347 return 0;
2348 else
2349 *property_id = id;
2350
2351 return 1;
2352}
2353
2354static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002355udev_drm_event(int fd, uint32_t mask, void *data)
2356{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002357 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002358 struct udev_device *event;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302359 uint32_t conn_id, prop_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002360
Giulio Camuffo954f1832014-10-11 18:27:30 +03002361 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002362
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302363 if (udev_event_is_hotplug(b, event)) {
2364 if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
2365 drm_backend_update_conn_props(b, conn_id, prop_id);
2366 else
2367 drm_backend_update_heads(b, event);
2368 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002369
2370 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002371
2372 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002373}
2374
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002375static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002376drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002377{
Armin Krezović545dba62016-08-05 15:54:18 +02002378 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002379 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002380
Giulio Camuffo954f1832014-10-11 18:27:30 +03002381 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002382
Giulio Camuffo954f1832014-10-11 18:27:30 +03002383 wl_event_source_remove(b->udev_drm_source);
2384 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002385
Daniel Stoneb57c6a02017-10-05 16:27:21 +01002386 b->shutting_down = true;
2387
Giulio Camuffo954f1832014-10-11 18:27:30 +03002388 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002389
Leandro Ribeirof0149642019-12-18 15:52:18 -03002390 weston_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002391 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002392 weston_compositor_shutdown(ec);
2393
Pekka Paalanenc112f002017-08-28 16:27:20 +03002394 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
2395 drm_head_destroy(to_drm_head(base));
2396
Stefan Agnerccf24072019-07-09 22:02:00 +02002397#ifdef BUILD_DRM_GBM
Giulio Camuffo954f1832014-10-11 18:27:30 +03002398 if (b->gbm)
2399 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02002400#endif
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002401
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02002402 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03002403 udev_unref(b->udev);
2404
Giulio Camuffo954f1832014-10-11 18:27:30 +03002405 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002406
Daniel Stone087ddf02017-02-14 17:51:30 +00002407 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00002408
Giulio Camuffo954f1832014-10-11 18:27:30 +03002409 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02002410 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002411 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002412}
2413
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002414static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002415session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002416{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002417 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02002418 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01002419 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002420 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002421
Giulio Camuffo954f1832014-10-11 18:27:30 +03002422 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002423 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00002424 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002425 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00002426 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002427 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002428 } else {
2429 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002430 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002431
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002432 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002433
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002434 /* If we have a repaint scheduled (either from a
2435 * pending pageflip or the idle handler), make sure we
2436 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002437 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002438 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002439 * back, we schedule a repaint, which will process
2440 * pending frame callbacks. */
2441
Giulio Camuffo954f1832014-10-11 18:27:30 +03002442 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00002443 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002444 if (output->cursor_plane)
2445 drmModeSetCursor(b->drm.fd, output->crtc_id,
2446 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002447 }
2448
Giulio Camuffo954f1832014-10-11 18:27:30 +03002449 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002450 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002451
Daniel Stone085d2b92015-05-21 00:00:57 +01002452 wl_list_for_each(plane, &b->plane_list, link) {
2453 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
2454 continue;
2455
Giulio Camuffo954f1832014-10-11 18:27:30 +03002456 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01002457 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002458 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002459 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01002460 }
2461 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002462}
2463
Robert Beckett8d23ab72019-06-13 16:55:44 +01002464
2465/**
2466 * Handle KMS GPU being added/removed
2467 *
2468 * If the device being added/removed is the KMS device, we activate/deactivate
2469 * the compositor session.
2470 *
2471 * @param compositor The compositor instance.
2472 * @param device The device being added/removed.
2473 * @param added Whether the device is being added (or removed)
2474 */
2475static void
2476drm_device_changed(struct weston_compositor *compositor,
2477 dev_t device, bool added)
2478{
2479 struct drm_backend *b = to_drm_backend(compositor);
2480
Robert Beckett49dc3202019-07-02 16:31:22 +01002481 if (b->drm.fd < 0 || b->drm.devnum != device ||
2482 compositor->session_active == added)
Robert Beckett8d23ab72019-06-13 16:55:44 +01002483 return;
2484
2485 compositor->session_active = added;
2486 wl_signal_emit(&compositor->session_signal, compositor);
2487}
2488
Daniel Stoneefa504f2016-12-19 16:48:20 +00002489/**
2490 * Determines whether or not a device is capable of modesetting. If successful,
2491 * sets b->drm.fd and b->drm.filename to the opened device.
2492 */
2493static bool
2494drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2495{
2496 const char *filename = udev_device_get_devnode(device);
2497 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002498 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002499 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02002500 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002501
2502 if (!filename)
2503 return false;
2504
2505 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
2506 if (fd < 0)
2507 return false;
2508
2509 res = drmModeGetResources(fd);
2510 if (!res)
2511 goto out_fd;
2512
2513 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2514 res->count_encoders <= 0)
2515 goto out_res;
2516
2517 if (sysnum)
2518 id = atoi(sysnum);
2519 if (!sysnum || id < 0) {
2520 weston_log("couldn't get sysnum for device %s\n", filename);
2521 goto out_res;
2522 }
2523
2524 /* We can be called successfully on multiple devices; if we have,
2525 * clean up old entries. */
2526 if (b->drm.fd >= 0)
2527 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2528 free(b->drm.filename);
2529
2530 b->drm.fd = fd;
2531 b->drm.id = id;
2532 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002533 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002534
Sergi Granellceb59812017-03-28 12:44:04 +02002535 drmModeFreeResources(res);
2536
Daniel Stoneefa504f2016-12-19 16:48:20 +00002537 return true;
2538
2539out_res:
2540 drmModeFreeResources(res);
2541out_fd:
2542 weston_launcher_close(b->compositor->launcher, fd);
2543 return false;
2544}
2545
David Herrmann0af066f2012-10-29 19:21:16 +01002546/*
2547 * Find primary GPU
2548 * Some systems may have multiple DRM devices attached to a single seat. This
2549 * function loops over all devices and tries to find a PCI device with the
2550 * boot_vga sysfs attribute set to 1.
2551 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00002552 * Devices are also vetted to make sure they are are capable of modesetting,
2553 * rather than pure render nodes (GPU with no display), or pure
2554 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01002555 */
2556static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002557find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002558{
2559 struct udev_enumerate *e;
2560 struct udev_list_entry *entry;
2561 const char *path, *device_seat, *id;
2562 struct udev_device *device, *drm_device, *pci;
2563
Giulio Camuffo954f1832014-10-11 18:27:30 +03002564 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002565 udev_enumerate_add_match_subsystem(e, "drm");
2566 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2567
2568 udev_enumerate_scan_devices(e);
2569 drm_device = NULL;
2570 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00002571 bool is_boot_vga = false;
2572
David Herrmann0af066f2012-10-29 19:21:16 +01002573 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002574 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002575 if (!device)
2576 continue;
2577 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2578 if (!device_seat)
2579 device_seat = default_seat;
2580 if (strcmp(device_seat, seat)) {
2581 udev_device_unref(device);
2582 continue;
2583 }
2584
2585 pci = udev_device_get_parent_with_subsystem_devtype(device,
2586 "pci", NULL);
2587 if (pci) {
2588 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00002589 if (id && !strcmp(id, "1"))
2590 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01002591 }
2592
Daniel Stoneefa504f2016-12-19 16:48:20 +00002593 /* If we already have a modesetting-capable device, and this
2594 * device isn't our boot-VGA device, we aren't going to use
2595 * it. */
2596 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01002597 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002598 continue;
2599 }
2600
2601 /* Make sure this device is actually capable of modesetting;
2602 * if this call succeeds, b->drm.{fd,filename} will be set,
2603 * and any old values freed. */
2604 if (!drm_device_is_kms(b, device)) {
2605 udev_device_unref(device);
2606 continue;
2607 }
2608
2609 /* There can only be one boot_vga device, and we try to use it
2610 * at all costs. */
2611 if (is_boot_vga) {
2612 if (drm_device)
2613 udev_device_unref(drm_device);
2614 drm_device = device;
2615 break;
2616 }
2617
2618 /* Per the (!is_boot_vga && drm_device) test above, we only
2619 * trump existing saved devices with boot-VGA devices, so if
2620 * we end up here, this must be the first device we've seen. */
2621 assert(!drm_device);
2622 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01002623 }
2624
Daniel Stoneefa504f2016-12-19 16:48:20 +00002625 /* If we're returning a device to use, we must have an open FD for
2626 * it. */
2627 assert(!!drm_device == (b->drm.fd >= 0));
2628
David Herrmann0af066f2012-10-29 19:21:16 +01002629 udev_enumerate_unref(e);
2630 return drm_device;
2631}
2632
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002633static struct udev_device *
2634open_specific_drm_device(struct drm_backend *b, const char *name)
2635{
2636 struct udev_device *device;
2637
2638 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2639 if (!device) {
2640 weston_log("ERROR: could not open DRM device '%s'\n", name);
2641 return NULL;
2642 }
2643
2644 if (!drm_device_is_kms(b, device)) {
2645 udev_device_unref(device);
2646 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2647 return NULL;
2648 }
2649
2650 /* If we're returning a device to use, we must have an open FD for
2651 * it. */
2652 assert(b->drm.fd >= 0);
2653
2654 return device;
2655}
2656
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002657static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002658planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2659 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002660{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002661 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002662
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002663 switch (key) {
2664 case KEY_C:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002665 b->cursors_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002666 break;
2667 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01002668 /* We don't support overlay-plane usage with legacy KMS. */
2669 if (b->atomic_modeset)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002670 b->sprites_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002671 break;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002672 default:
2673 break;
2674 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002675}
2676
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002677#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002678static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002679recorder_destroy(struct drm_output *output)
2680{
2681 vaapi_recorder_destroy(output->recorder);
2682 output->recorder = NULL;
2683
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302684 weston_output_disable_planes_decr(&output->base);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002685
2686 wl_list_remove(&output->recorder_frame_listener.link);
2687 weston_log("[libva recorder] done\n");
2688}
2689
2690static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002691recorder_frame_notify(struct wl_listener *listener, void *data)
2692{
2693 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002694 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002695 int fd, ret;
2696
2697 output = container_of(listener, struct drm_output,
2698 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02002699 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002700
2701 if (!output->recorder)
2702 return;
2703
Daniel Stonee2e80132018-01-16 15:37:33 +00002704 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002705 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002706 DRM_CLOEXEC, &fd);
2707 if (ret) {
2708 weston_log("[libva recorder] "
2709 "failed to create prime fd for front buffer\n");
2710 return;
2711 }
2712
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002713 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002714 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002715 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002716 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002717 recorder_destroy(output);
2718 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002719}
2720
2721static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002722create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002723 const char *filename)
2724{
2725 int fd;
2726 drm_magic_t magic;
2727
Giulio Camuffo954f1832014-10-11 18:27:30 +03002728 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002729 if (fd < 0)
2730 return NULL;
2731
2732 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002733 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002734
2735 return vaapi_recorder_create(fd, width, height, filename);
2736}
2737
2738static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002739recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2740 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002741{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002742 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002743 struct drm_output *output;
2744 int width, height;
2745
Giulio Camuffo954f1832014-10-11 18:27:30 +03002746 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002747 struct drm_output, base.link);
2748
2749 if (!output->recorder) {
Stefan Agner4a18f302019-10-20 18:25:42 +02002750 if (output->gbm_format != DRM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002751 weston_log("failed to start vaapi recorder: "
2752 "output format not supported\n");
2753 return;
2754 }
2755
Hardeningff39efa2013-09-18 23:56:35 +02002756 width = output->base.current_mode->width;
2757 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002758
2759 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002760 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002761 if (!output->recorder) {
2762 weston_log("failed to create vaapi recorder\n");
2763 return;
2764 }
2765
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302766 weston_output_disable_planes_incr(&output->base);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002767
2768 output->recorder_frame_listener.notify = recorder_frame_notify;
2769 wl_signal_add(&output->base.frame_signal,
2770 &output->recorder_frame_listener);
2771
2772 weston_output_schedule_repaint(&output->base);
2773
2774 weston_log("[libva recorder] initialized\n");
2775 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002776 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002777 }
2778}
2779#else
2780static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002781recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2782 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002783{
2784 weston_log("Compiled without libva support\n");
2785}
2786#endif
2787
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002788
Armin Krezović08368132016-09-30 14:11:05 +02002789static const struct weston_drm_output_api api = {
2790 drm_output_set_mode,
2791 drm_output_set_gbm_format,
2792 drm_output_set_seat,
2793};
2794
Giulio Camuffo954f1832014-10-11 18:27:30 +03002795static struct drm_backend *
2796drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002797 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002798{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002799 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01002800 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002801 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002802 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04002803 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02002804 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002805
nerdopolisb16c4ac2018-06-29 08:17:46 -04002806 session_seat = getenv("XDG_SEAT");
2807 if (session_seat)
2808 seat_id = session_seat;
2809
2810 if (config->seat_id)
2811 seat_id = config->seat_id;
2812
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002813 weston_log("initializing drm backend\n");
2814
Giulio Camuffo954f1832014-10-11 18:27:30 +03002815 b = zalloc(sizeof *b);
2816 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002817 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002818
Daniel Stone6020f472018-02-05 15:46:20 +00002819 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002820 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00002821 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002822
Giulio Camuffo954f1832014-10-11 18:27:30 +03002823 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002824 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002825 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02002826 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002827
Leandro Ribeiro172afc22019-12-26 16:23:43 -03002828 b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
2829 "Debug messages from DRM/KMS backend\n",
2830 NULL, NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002831
Pekka Paalanen7da9a382017-08-30 11:29:49 +03002832 compositor->backend = &b->base;
2833
Stefan Agner0bfebeb2019-07-08 00:30:44 +02002834 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002835 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002836
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002837 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002838 compositor->launcher = weston_launcher_connect(compositor, config->tty,
2839 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002840 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02002841 weston_log("fatal: drm backend should be run using "
2842 "weston-launch binary, or your system should "
2843 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002844 goto err_compositor;
2845 }
2846
Giulio Camuffo954f1832014-10-11 18:27:30 +03002847 b->udev = udev_new();
2848 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002849 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002850 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002851 }
2852
Giulio Camuffo954f1832014-10-11 18:27:30 +03002853 b->session_listener.notify = session_notify;
2854 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002855
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002856 if (config->specific_device)
2857 drm_device = open_specific_drm_device(b, config->specific_device);
2858 else
2859 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002860 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002861 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002862 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002863 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002864
Daniel Stoneefa504f2016-12-19 16:48:20 +00002865 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002866 weston_log("failed to initialize kms\n");
2867 goto err_udev_dev;
2868 }
2869
Giulio Camuffo954f1832014-10-11 18:27:30 +03002870 if (b->use_pixman) {
2871 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002872 weston_log("failed to initialize pixman renderer\n");
2873 goto err_udev_dev;
2874 }
2875 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002876 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002877 weston_log("failed to initialize egl\n");
2878 goto err_udev_dev;
2879 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002880 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002881
Giulio Camuffo954f1832014-10-11 18:27:30 +03002882 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002883 b->base.repaint_begin = drm_repaint_begin;
2884 b->base.repaint_flush = drm_repaint_flush;
2885 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002886 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01002887 b->base.device_changed = drm_device_changed;
Marius Vlad81bada52019-11-11 00:27:17 +02002888 b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002889
Bob Ham91880f12016-01-12 10:21:47 +00002890 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002891
Daniel Stone085d2b92015-05-21 00:00:57 +01002892 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002893 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002894
Giulio Camuffo954f1832014-10-11 18:27:30 +03002895 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03002896 compositor, b->udev, seat_id,
2897 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002898 weston_log("failed to create input devices\n");
2899 goto err_sprite;
2900 }
2901
Pekka Paalanend2e62422017-09-08 15:48:07 +03002902 if (drm_backend_create_heads(b, drm_device) < 0) {
2903 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002904 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002905 }
2906
Marius Vlade83e7502019-10-29 17:29:37 +02002907 /* 'compute' faked zpos values in case HW doesn't expose any */
2908 drm_backend_create_faked_zpos(b);
2909
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002910 /* A this point we have some idea of whether or not we have a working
2911 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002912 if (!b->cursors_are_broken)
2913 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002914
Giulio Camuffo954f1832014-10-11 18:27:30 +03002915 loop = wl_display_get_event_loop(compositor->wl_display);
2916 b->drm_source =
2917 wl_event_loop_add_fd(loop, b->drm.fd,
2918 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002919
Giulio Camuffo954f1832014-10-11 18:27:30 +03002920 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
2921 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002922 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002923 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002924 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002925 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002926 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002927 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002928 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002929 udev_monitor_get_fd(b->udev_monitor),
2930 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002931
Giulio Camuffo954f1832014-10-11 18:27:30 +03002932 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002933 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002934 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002935 }
2936
Daniel Stonea96b93c2012-06-22 14:04:37 +01002937 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002938
Giulio Camuffo954f1832014-10-11 18:27:30 +03002939 weston_compositor_add_debug_binding(compositor, KEY_O,
2940 planes_binding, b);
2941 weston_compositor_add_debug_binding(compositor, KEY_C,
2942 planes_binding, b);
2943 weston_compositor_add_debug_binding(compositor, KEY_V,
2944 planes_binding, b);
2945 weston_compositor_add_debug_binding(compositor, KEY_Q,
2946 recorder_binding, b);
2947 weston_compositor_add_debug_binding(compositor, KEY_W,
2948 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002949
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002950 if (compositor->renderer->import_dmabuf) {
2951 if (linux_dmabuf_setup(compositor) < 0)
2952 weston_log("Error: initializing dmabuf "
2953 "support failed.\n");
Marius Vladebd10e52019-11-16 19:22:48 +02002954 if (weston_direct_display_setup(compositor) < 0)
2955 weston_log("Error: initializing direct-display "
2956 "support failed.\n");
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002957 }
2958
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002959 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
2960 if (linux_explicit_synchronization_setup(compositor) < 0)
2961 weston_log("Error: initializing explicit "
2962 " synchronization support failed.\n");
2963 }
2964
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302965 if (b->atomic_modeset)
2966 if (weston_compositor_enable_content_protection(compositor) < 0)
2967 weston_log("Error: initializing content-protection "
2968 "support failed.\n");
2969
Armin Krezović08368132016-09-30 14:11:05 +02002970 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
2971 &api, sizeof(api));
2972
2973 if (ret < 0) {
2974 weston_log("Failed to register output API.\n");
2975 goto err_udev_monitor;
2976 }
2977
Stefan Agner3654c672019-07-09 00:50:30 +02002978 ret = drm_backend_init_virtual_output_api(compositor);
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002979 if (ret < 0) {
2980 weston_log("Failed to register virtual output API.\n");
2981 goto err_udev_monitor;
2982 }
2983
Giulio Camuffo954f1832014-10-11 18:27:30 +03002984 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002985
2986err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002987 wl_event_source_remove(b->udev_drm_source);
2988 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002989err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002990 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002991err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002992 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002993err_sprite:
Stefan Agnerccf24072019-07-09 22:02:00 +02002994#ifdef BUILD_DRM_GBM
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01002995 if (b->gbm)
2996 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02002997#endif
Giulio Camuffo954f1832014-10-11 18:27:30 +03002998 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002999err_udev_dev:
3000 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003001err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003002 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003003err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003004 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003005err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003006 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003007 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003008 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003009}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003010
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003011static void
3012config_init_to_defaults(struct weston_drm_backend_config *config)
3013{
Pekka Paalanendee412d2018-04-23 11:44:58 +02003014 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003015}
3016
Giulio Camuffo954f1832014-10-11 18:27:30 +03003017WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01003018weston_backend_init(struct weston_compositor *compositor,
3019 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003020{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003021 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003022 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003023
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003024 if (config_base == NULL ||
3025 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3026 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3027 weston_log("drm backend config structure is invalid\n");
3028 return -1;
3029 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02003030
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003031 config_init_to_defaults(&config);
3032 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003033
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003034 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003035 if (b == NULL)
3036 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003037
Giulio Camuffo954f1832014-10-11 18:27:30 +03003038 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003039}