blob: 5fb203555f9b0bdb51498626bb49bb78cb20d109 [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 Oliveira97f29522013-10-14 15:57:11 +030043#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030044#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Benjamin Franzkec649a922011-03-02 11:56:04 +010046#include <xf86drm.h>
47#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050048#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010049
Pekka Paalanen33156972012-08-03 13:30:30 -040050#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020051
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020052#include <libweston/libweston.h>
Pekka Paalanen75710272019-03-29 16:39:12 +020053#include <libweston/backend-drm.h>
Marius Vladf4f4c2b2019-04-29 13:27:47 +030054#include <libweston/weston-debug.h>
Daniel Stonedd1bc502019-06-17 12:13:46 +010055#include "drm-internal.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070056#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020057#include "shared/timespec-util.h"
Pekka Paalanen81475a52019-04-04 17:29:27 +030058#include "renderer-gl/gl-renderer.h"
Vincent Abriouc9506672016-10-05 16:14:07 +020059#include "weston-egl-ext.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020060#include "pixman-renderer.h"
Daniel Stone0b70fa42017-04-04 17:54:23 +010061#include "pixel-formats.h"
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070062#include "libbacklight.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100063#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010064#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030065#include "vaapi-recorder.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020066#include "presentation-time-server-protocol.h"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030067#include "linux-dmabuf.h"
Micah Fedkec8890122017-02-01 15:28:23 -050068#include "linux-dmabuf-unstable-v1-server-protocol.h"
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030069#include "linux-explicit-synchronization.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040070
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030071static struct gl_renderer_interface *gl_renderer;
72
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050073static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -040074
Daniel Stone087ddf02017-02-14 17:51:30 +000075static void
76wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
77{
78 uint32_t *pos, *end;
79
80 end = (uint32_t *) ((char *) array->data + array->size);
81
82 wl_array_for_each(pos, array) {
83 if (*pos != elm)
84 continue;
85
86 array->size -= sizeof(*pos);
87 if (pos + 1 == end)
88 break;
89
90 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
91 break;
92 }
93}
94
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +000095static int
96pageflip_timeout(void *data) {
97 /*
98 * Our timer just went off, that means we're not receiving drm
99 * page flip events anymore for that output. Let's gracefully exit
100 * weston with a return value so devs can debug what's going on.
101 */
102 struct drm_output *output = data;
103 struct weston_compositor *compositor = output->base.compositor;
104
105 weston_log("Pageflip timeout reached on output %s, your "
106 "driver is probably buggy! Exiting.\n",
107 output->base.name);
108 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
109
110 return 0;
111}
112
113/* Creates the pageflip timer. Note that it isn't armed by default */
114static int
115drm_output_pageflip_timer_create(struct drm_output *output)
116{
117 struct wl_event_loop *loop = NULL;
118 struct weston_compositor *ec = output->base.compositor;
119
120 loop = wl_display_get_event_loop(ec->wl_display);
121 assert(loop);
122 output->pageflip_timer = wl_event_loop_add_timer(loop,
123 pageflip_timeout,
124 output);
125
126 if (output->pageflip_timer == NULL) {
Antonio Borneo39578632019-04-26 23:57:31 +0200127 weston_log("creating drm pageflip timer failed: %s\n",
128 strerror(errno));
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000129 return -1;
130 }
131
132 return 0;
133}
134
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000135static void
136drm_output_destroy(struct weston_output *output_base);
137
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900138static void
139drm_virtual_output_destroy(struct weston_output *output_base);
140
Daniel Stone5ff289a2017-10-07 12:59:02 +0100141/**
142 * Returns true if the plane can be used on the given output for its current
143 * repaint cycle.
144 */
Daniel Stonee404b722019-06-22 18:40:31 +0100145bool
Daniel Stone5ff289a2017-10-07 12:59:02 +0100146drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500147{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100148 assert(plane->state_cur);
149
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900150 if (output->virtual)
151 return false;
152
Daniel Stone5ff289a2017-10-07 12:59:02 +0100153 /* The plane still has a request not yet completed by the kernel. */
154 if (!plane->state_cur->complete)
155 return false;
156
157 /* The plane is still active on another output. */
158 if (plane->state_cur->output && plane->state_cur->output != output)
159 return false;
160
161 /* Check whether the plane can be used with this CRTC; possible_crtcs
162 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100163 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500164}
165
Daniel Stone4c2fc702019-06-18 11:12:07 +0100166struct drm_output *
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000167drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
168{
169 struct drm_output *output;
170
171 wl_list_for_each(output, &b->compositor->output_list, base.link) {
172 if (output->crtc_id == crtc_id)
173 return output;
174 }
175
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000176 return NULL;
177}
178
Daniel Stone4c2fc702019-06-18 11:12:07 +0100179struct drm_head *
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300180drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
181{
182 struct weston_head *base;
183 struct drm_head *head;
184
185 wl_list_for_each(base,
186 &backend->compositor->head_list, compositor_link) {
187 head = to_drm_head(base);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300188 if (head->connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300189 return head;
190 }
191
192 return NULL;
193}
194
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000195/**
Daniel Stonea08512f2016-11-08 17:46:10 +0000196 * Get output state to disable output
197 *
198 * Returns a pointer to an output_state object which can be used to disable
199 * an output (e.g. DPMS off).
200 *
201 * @param pending_state The pending state object owning this update
202 * @param output The output to disable
203 * @returns A drm_output_state to disable the output
204 */
205static struct drm_output_state *
206drm_output_get_disable_state(struct drm_pending_state *pending_state,
207 struct drm_output *output)
208{
209 struct drm_output_state *output_state;
210
211 output_state = drm_output_state_duplicate(output->state_cur,
212 pending_state,
213 DRM_OUTPUT_STATE_CLEAR_PLANES);
214 output_state->dpms = WESTON_DPMS_OFF;
215
216 return output_state;
217}
218
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000219
220/**
221 * Mark a drm_output_state (the output's last state) as complete. This handles
222 * any post-completion actions such as updating the repaint timer, disabling the
223 * output, and finally freeing the state.
224 */
Daniel Stone4c2fc702019-06-18 11:12:07 +0100225void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000226drm_output_update_complete(struct drm_output *output, uint32_t flags,
227 unsigned int sec, unsigned int usec)
228{
Daniel Stonea08512f2016-11-08 17:46:10 +0000229 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +0000230 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000231 struct timespec ts;
232
233 /* Stop the pageflip timer instead of rearming it here */
234 if (output->pageflip_timer)
235 wl_event_source_timer_update(output->pageflip_timer, 0);
236
Daniel Stonebc15f682016-11-14 16:57:01 +0000237 wl_list_for_each(ps, &output->state_cur->plane_list, link)
238 ps->complete = true;
239
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000240 drm_output_state_free(output->state_last);
241 output->state_last = NULL;
242
243 if (output->destroy_pending) {
Daniel Stonea08512f2016-11-08 17:46:10 +0000244 output->destroy_pending = 0;
245 output->disable_pending = 0;
246 output->dpms_off_pending = 0;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000247 drm_output_destroy(&output->base);
248 return;
249 } else if (output->disable_pending) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000250 output->disable_pending = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +0000251 output->dpms_off_pending = 0;
252 weston_output_disable(&output->base);
253 return;
254 } else if (output->dpms_off_pending) {
255 struct drm_pending_state *pending = drm_pending_state_alloc(b);
256 output->dpms_off_pending = 0;
257 drm_output_get_disable_state(pending, output);
258 drm_pending_state_apply_sync(pending);
Daniel Stonea08512f2016-11-08 17:46:10 +0000259 } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
260 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
261 /* DPMS can happen to us either in the middle of a repaint
262 * cycle (when we have painted fresh content, only to throw it
263 * away for DPMS off), or at any other random point. If the
264 * latter is true, then we cannot go through finish_frame,
265 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000266 return;
267 }
268
269 ts.tv_sec = sec;
270 ts.tv_nsec = usec * 1000;
271 weston_output_finish_frame(&output->base, &ts, flags);
272
273 /* We can't call this from frame_notify, because the output's
274 * repaint needed flag is cleared just after that */
275 if (output->recorder)
276 weston_output_schedule_repaint(&output->base);
277}
278
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500279
Daniel Stone95d48a22017-04-04 17:54:30 +0100280static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000281drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400282{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000283 struct drm_output *output = state->output;
Armin Krezović545dba62016-08-05 15:54:18 +0200284 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300285 struct gbm_bo *bo;
Daniel Stone95d48a22017-04-04 17:54:30 +0100286 struct drm_fb *ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400287
Giulio Camuffo954f1832014-10-11 18:27:30 +0300288 output->base.compositor->renderer->repaint_output(&output->base,
289 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400290
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100291 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300292 if (!bo) {
Antonio Borneo39578632019-04-26 23:57:31 +0200293 weston_log("failed to lock front buffer: %s\n",
294 strerror(errno));
Daniel Stone95d48a22017-04-04 17:54:30 +0100295 return NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400296 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300297
Daniel Stonedb10df12016-12-08 13:15:58 +0000298 /* The renderer always produces an opaque image. */
299 ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE);
Daniel Stone95d48a22017-04-04 17:54:30 +0100300 if (!ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200301 weston_log("failed to get drm_fb for bo\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100302 gbm_surface_release_buffer(output->gbm_surface, bo);
Daniel Stone95d48a22017-04-04 17:54:30 +0100303 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300304 }
Daniel Stone95d48a22017-04-04 17:54:30 +0100305 ret->gbm_surface = output->gbm_surface;
306
307 return ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400308}
309
Daniel Stone95d48a22017-04-04 17:54:30 +0100310static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000311drm_output_render_pixman(struct drm_output_state *state,
312 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200313{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000314 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200315 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200316
317 output->current_image ^= 1;
318
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200319 pixman_renderer_output_set_buffer(&output->base,
320 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200321 pixman_renderer_output_set_hw_extra_damage(&output->base,
322 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200323
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200324 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200325
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200326 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +0100327
328 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200329}
330
331static void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000332drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200333{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000334 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300335 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +0000336 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +0000337 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +0200338 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +0100339 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200340
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100341 /* If we already have a client buffer promoted to scanout, then we don't
342 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +0000343 scanout_state = drm_output_state_get_plane(state,
344 output->scanout_plane);
345 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100346 return;
347
Daniel Stonee95169b2016-11-14 17:46:59 +0000348 if (!pixman_region32_not_empty(damage) &&
349 scanout_plane->state_cur->fb &&
350 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
351 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
352 scanout_plane->state_cur->fb->width ==
353 output->base.current_mode->width &&
354 scanout_plane->state_cur->fb->height ==
355 output->base.current_mode->height) {
356 fb = drm_fb_ref(scanout_plane->state_cur->fb);
357 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000358 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000359 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000360 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000361 }
Daniel Stone95d48a22017-04-04 17:54:30 +0100362
Daniel Stonee2e80132018-01-16 15:37:33 +0000363 if (!fb) {
364 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +0100365 return;
Daniel Stonee2e80132018-01-16 15:37:33 +0000366 }
367
368 scanout_state->fb = fb;
369 scanout_state->output = output;
370
371 scanout_state->src_x = 0;
372 scanout_state->src_y = 0;
373 scanout_state->src_w = output->base.current_mode->width << 16;
374 scanout_state->src_h = output->base.current_mode->height << 16;
375
376 scanout_state->dest_x = 0;
377 scanout_state->dest_y = 0;
378 scanout_state->dest_w = scanout_state->src_w >> 16;
379 scanout_state->dest_h = scanout_state->src_h >> 16;
380
Deepak Rawat46a1c722018-07-24 14:13:34 -0700381 pixman_region32_copy(&scanout_state->damage, damage);
382 if (output->base.zoom.active) {
383 weston_matrix_transform_region(&scanout_state->damage,
384 &output->base.matrix,
385 &scanout_state->damage);
386 } else {
387 pixman_region32_translate(&scanout_state->damage,
388 -output->base.x, -output->base.y);
389 weston_transformed_region(output->base.width,
390 output->base.height,
391 output->base.transform,
392 output->base.current_scale,
393 &scanout_state->damage,
394 &scanout_state->damage);
395 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200396
Giulio Camuffo954f1832014-10-11 18:27:30 +0300397 pixman_region32_subtract(&c->primary_plane.damage,
398 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200399}
400
Daniel Stonea08512f2016-11-08 17:46:10 +0000401static int
402drm_output_repaint(struct weston_output *output_base,
403 pixman_region32_t *damage,
404 void *repaint_data)
405{
406 struct drm_pending_state *pending_state = repaint_data;
407 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +0000408 struct drm_output_state *state = NULL;
409 struct drm_plane_state *scanout_state;
410
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900411 assert(!output->virtual);
412
Daniel Stonea08512f2016-11-08 17:46:10 +0000413 if (output->disable_pending || output->destroy_pending)
414 goto err;
415
416 assert(!output->state_last);
417
418 /* If planes have been disabled in the core, we might not have
419 * hit assign_planes at all, so might not have valid output state
420 * here. */
421 state = drm_pending_state_get_output(pending_state, output);
422 if (!state)
423 state = drm_output_state_duplicate(output->state_cur,
424 pending_state,
425 DRM_OUTPUT_STATE_CLEAR_PLANES);
426 state->dpms = WESTON_DPMS_ON;
427
428 drm_output_render(state, damage);
429 scanout_state = drm_output_state_get_plane(state,
430 output->scanout_plane);
431 if (!scanout_state || !scanout_state->fb)
432 goto err;
433
Daniel Stonea08512f2016-11-08 17:46:10 +0000434 return 0;
435
436err:
437 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +0200438 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400439}
440
Daniel Stone4c2fc702019-06-18 11:12:07 +0100441/* Determine the type of vblank synchronization to use for the output.
442 *
443 * The pipe parameter indicates which CRTC is in use. Knowing this, we
444 * can determine which vblank sequence type to use for it. Traditional
445 * cards had only two CRTCs, with CRTC 0 using no special flags, and
446 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
447 * parameter indicates this.
448 *
449 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
450 * 0-31. If this is non-zero it indicates we're dealing with a
451 * multi-gpu situation and we need to calculate the vblank sync
452 * using DRM_BLANK_HIGH_CRTC_MASK.
453 */
454static unsigned int
455drm_waitvblank_pipe(struct drm_output *output)
456{
457 if (output->pipe > 1)
458 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
459 DRM_VBLANK_HIGH_CRTC_MASK;
460 else if (output->pipe > 0)
461 return DRM_VBLANK_SECONDARY;
462 else
463 return 0;
464}
465
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200466static int
Jonas Ådahle5a12252013-04-05 23:07:11 +0200467drm_output_start_repaint_loop(struct weston_output *output_base)
468{
Armin Krezović545dba62016-08-05 15:54:18 +0200469 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +0000470 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +0000471 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +0200472 struct drm_backend *backend =
473 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200474 struct timespec ts, tnow;
475 struct timespec vbl2now;
476 int64_t refresh_nsec;
477 int ret;
478 drmVBlank vbl = {
479 .request.type = DRM_VBLANK_RELATIVE,
480 .request.sequence = 0,
481 .request.signal = 0,
482 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300483
Armin Krezović08368132016-09-30 14:11:05 +0200484 if (output->disable_pending || output->destroy_pending)
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200485 return 0;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800486
Daniel Stonee2e80132018-01-16 15:37:33 +0000487 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300488 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200489 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300490 }
491
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300492 /* Need to smash all state in from scratch; current timings might not
493 * be what we want, page flip might not work, etc.
494 */
Daniel Stone6020f472018-02-05 15:46:20 +0000495 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300496 goto finish_frame;
497
Daniel Stonee2e80132018-01-16 15:37:33 +0000498 assert(scanout_plane->state_cur->output == output);
499
Mario Kleinerf507ec32015-06-21 21:25:14 +0200500 /* Try to get current msc and timestamp via instant query */
501 vbl.request.type |= drm_waitvblank_pipe(output);
502 ret = drmWaitVBlank(backend->drm.fd, &vbl);
503
504 /* Error ret or zero timestamp means failure to get valid timestamp */
505 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
506 ts.tv_sec = vbl.reply.tval_sec;
507 ts.tv_nsec = vbl.reply.tval_usec * 1000;
508
509 /* Valid timestamp for most recent vblank - not stale?
510 * Stale ts could happen on Linux 3.17+, so make sure it
511 * is not older than 1 refresh duration since now.
512 */
513 weston_compositor_read_presentation_clock(backend->compositor,
514 &tnow);
515 timespec_sub(&vbl2now, &tnow, &ts);
516 refresh_nsec =
517 millihz_to_nsec(output->base.current_mode->refresh);
518 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
519 drm_output_update_msc(output, vbl.reply.sequence);
520 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200521 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200522 return 0;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200523 }
524 }
525
526 /* Immediate query didn't provide valid timestamp.
527 * Use pageflip fallback.
528 */
Jonas Ådahle5a12252013-04-05 23:07:11 +0200529
Daniel Stone205c0a02017-04-04 17:54:33 +0100530 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000531 assert(!output->state_last);
532
533 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +0000534 drm_output_state_duplicate(output->state_cur, pending_state,
535 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +0100536
Daniel Stone8747f952016-11-29 20:17:32 +0000537 ret = drm_pending_state_apply(pending_state);
538 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200539 weston_log("applying repaint-start state failed: %s\n",
540 strerror(errno));
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200541 if (ret == -EACCES)
542 return -1;
David Herrmann3c688c52013-10-22 17:11:25 +0200543 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200544 }
David Herrmann3c688c52013-10-22 17:11:25 +0200545
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200546 return 0;
David Herrmann3c688c52013-10-22 17:11:25 +0200547
548finish_frame:
549 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +0000550 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200551 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200552 return 0;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200553}
554
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000555/**
556 * Begin a new repaint cycle
557 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000558 * Called by the core compositor at the beginning of a repaint cycle. Creates
559 * a new pending_state structure to own any output state created by individual
560 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000561 */
562static void *
563drm_repaint_begin(struct weston_compositor *compositor)
564{
565 struct drm_backend *b = to_drm_backend(compositor);
566 struct drm_pending_state *ret;
567
568 ret = drm_pending_state_alloc(b);
569 b->repaint_data = ret;
570
Marius Vlad7e4db952019-04-17 13:47:06 +0300571 if (weston_log_scope_is_enabled(b->debug)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100572 char *dbg = weston_compositor_print_scene_graph(compositor);
573 drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
574 ret);
575 drm_debug(b, "%s", dbg);
576 free(dbg);
577 }
578
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000579 return ret;
580}
581
582/**
583 * Flush a repaint set
584 *
585 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000586 * and should be flushed. Frees the pending state, transitioning ownership
587 * of the output state from the pending state, to the update itself. When
588 * the update completes (see drm_output_update_complete), the output
589 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000590 */
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200591static int
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000592drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
593{
594 struct drm_backend *b = to_drm_backend(compositor);
595 struct drm_pending_state *pending_state = repaint_data;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200596 int ret;
Daniel Stone6020f472018-02-05 15:46:20 +0000597
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200598 ret = drm_pending_state_apply(pending_state);
599 if (ret != 0)
600 weston_log("repaint-flush failed: %s\n", strerror(errno));
601
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100602 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000603 b->repaint_data = NULL;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200604
605 return (ret == -EACCES) ? -1 : 0;
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000606}
607
608/**
609 * Cancel a repaint set
610 *
611 * Called by the core compositor when a repaint has finished, so the data
612 * held across the repaint cycle should be discarded.
613 */
614static void
615drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
616{
617 struct drm_backend *b = to_drm_backend(compositor);
618 struct drm_pending_state *pending_state = repaint_data;
619
620 drm_pending_state_free(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100621 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000622 b->repaint_data = NULL;
623}
624
Alex Wub7b8bda2012-04-17 17:20:48 +0800625static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300626drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +0000627static void
628drm_output_fini_egl(struct drm_output *output);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200629static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300630drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +0000631static void
632drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200633
634static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800635drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
636{
Daniel Stone02d487a2017-10-07 14:01:45 +0100637 struct drm_output *output = to_drm_output(output_base);
638 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stonefbe6c1d2019-06-17 16:04:26 +0100639 struct drm_mode *drm_mode = drm_output_choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +0800640
641 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +0100642 weston_log("%s: invalid resolution %dx%d\n",
643 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800644 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200645 }
646
Hardeningff39efa2013-09-18 23:56:35 +0200647 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +0800648 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800649
Hardeningff39efa2013-09-18 23:56:35 +0200650 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800651
Hardeningff39efa2013-09-18 23:56:35 +0200652 output->base.current_mode = &drm_mode->base;
653 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800654 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
655
Daniel Stonef30a18c2017-04-04 17:54:31 +0100656 /* XXX: This drops our current buffer too early, before we've started
657 * displaying it. Ideally this should be much more atomic and
658 * integrated with a full repaint cycle, rather than doing a
659 * sledgehammer modeswitch first, and only later showing new
660 * content.
661 */
Daniel Stone6020f472018-02-05 15:46:20 +0000662 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +0800663
Giulio Camuffo954f1832014-10-11 18:27:30 +0300664 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200665 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300666 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200667 weston_log("failed to init output pixman state with "
668 "new mode\n");
669 return -1;
670 }
671 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +0000672 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300673 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200674 weston_log("failed to init output egl state with "
675 "new mode");
676 return -1;
677 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200678 }
679
Alex Wub7b8bda2012-04-17 17:20:48 +0800680 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800681}
682
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200683static struct gbm_device *
684create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +0200685{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200686 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +0100687
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300688 gl_renderer = weston_load_module("gl-renderer.so",
689 "gl_renderer_interface");
690 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200691 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300692
693 /* GBM will load a dri driver, but even though they need symbols from
694 * libglapi, in some version of Mesa they are not linked to it. Since
695 * only the gl-renderer module links to it, the call above won't make
696 * these symbols globally available, and loading the DRI driver fails.
697 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
698 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
699
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200700 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400701
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200702 return gbm;
703}
704
Bryce Harringtonc056a982015-05-19 15:25:18 -0700705/* When initializing EGL, if the preferred buffer format isn't available
Bryce Harringtonb9939982016-04-15 20:28:26 -0700706 * we may be able to substitute an ARGB format for an XRGB one.
Derek Foremanc4cfe852015-05-15 12:12:40 -0500707 *
708 * This returns 0 if substitution isn't possible, but 0 might be a
709 * legitimate format for other EGL platforms, so the caller is
710 * responsible for checking for 0 before calling gl_renderer->create().
711 *
712 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
713 * but it's entirely possible we'll see this again on other implementations.
714 */
715static int
716fallback_format_for(uint32_t format)
717{
718 switch (format) {
719 case GBM_FORMAT_XRGB8888:
720 return GBM_FORMAT_ARGB8888;
721 case GBM_FORMAT_XRGB2101010:
722 return GBM_FORMAT_ARGB2101010;
723 default:
724 return 0;
725 }
726}
727
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200728static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300729drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200730{
Derek Foreman6d556372015-11-04 14:47:33 -0600731 EGLint format[3] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100732 b->gbm_format,
733 fallback_format_for(b->gbm_format),
Derek Foreman6d556372015-11-04 14:47:33 -0600734 0,
Derek Foremanc4cfe852015-05-15 12:12:40 -0500735 };
Derek Foreman6d556372015-11-04 14:47:33 -0600736 int n_formats = 2;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +0100737
Derek Foremanc4cfe852015-05-15 12:12:40 -0500738 if (format[1])
Derek Foreman6d556372015-11-04 14:47:33 -0600739 n_formats = 3;
Miguel A. Vicodddc6702016-05-18 17:41:07 +0200740 if (gl_renderer->display_create(b->compositor,
741 EGL_PLATFORM_GBM_KHR,
742 (void *)b->gbm,
Miguel A. Vico41700e32016-05-18 17:47:59 +0200743 NULL,
Miguel A. Vicodddc6702016-05-18 17:41:07 +0200744 gl_renderer->opaque_attribs,
745 format,
746 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200747 return -1;
748 }
749
750 return 0;
751}
752
753static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300754init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200755{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300756 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200757
Giulio Camuffo954f1832014-10-11 18:27:30 +0300758 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200759 return -1;
760
Giulio Camuffo954f1832014-10-11 18:27:30 +0300761 if (drm_backend_create_gl_renderer(b) < 0) {
762 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400763 return -1;
764 }
765
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400766 return 0;
767}
768
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200769static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300770init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200771{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300772 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200773}
774
Sergi Granellf4456222017-01-12 17:17:32 +0000775
Pekka Paalanen7b36b422014-06-04 14:00:53 +0300776/**
Pekka Paalanenec272712014-06-05 11:22:25 +0300777 * Create a drm_plane for a hardware plane
778 *
779 * Creates one drm_plane structure for a hardware plane, and initialises its
780 * properties and formats.
781 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100782 * In the absence of universal plane support, where KMS does not explicitly
783 * expose the primary and cursor planes to userspace, this may also create
784 * an 'internal' plane for internal management.
785 *
Pekka Paalanenec272712014-06-05 11:22:25 +0300786 * This function does not add the plane to the list of usable planes in Weston
787 * itself; the caller is responsible for this.
788 *
789 * Call drm_plane_destroy to clean up the plane.
790 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100791 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +0300792 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +0100793 * @param kplane DRM plane to create, or NULL if creating internal plane
794 * @param output Output to create internal plane for, or NULL
795 * @param type Type to use when creating internal plane, or invalid
796 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +0300797 */
798static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100799drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
800 struct drm_output *output, enum wdrm_plane_type type,
801 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +0300802{
803 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100804 drmModeObjectProperties *props;
Sergi Granellf4456222017-01-12 17:17:32 +0000805 uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100806
Daniel Stone2ba17f42015-05-19 20:02:41 +0100807 plane = zalloc(sizeof(*plane) +
Sergi Granellf4456222017-01-12 17:17:32 +0000808 (sizeof(plane->formats[0]) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +0300809 if (!plane) {
810 weston_log("%s: out of memory\n", __func__);
811 return NULL;
812 }
813
814 plane->backend = b;
Sergi Granellf4456222017-01-12 17:17:32 +0000815 plane->count_formats = num_formats;
Daniel Stonebc15f682016-11-14 16:57:01 +0000816 plane->state_cur = drm_plane_state_alloc(NULL, plane);
817 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +0300818
Daniel Stone2ba17f42015-05-19 20:02:41 +0100819 if (kplane) {
820 plane->possible_crtcs = kplane->possible_crtcs;
821 plane->plane_id = kplane->plane_id;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100822
823 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
824 DRM_MODE_OBJECT_PLANE);
825 if (!props) {
826 weston_log("couldn't get plane properties\n");
827 goto err;
828 }
829 drm_property_info_populate(b, plane_props, plane->props,
830 WDRM_PLANE__COUNT, props);
831 plane->type =
832 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
833 props,
834 WDRM_PLANE_TYPE__COUNT);
Sergi Granellf4456222017-01-12 17:17:32 +0000835
836 if (drm_plane_populate_formats(plane, kplane, props) < 0) {
837 drmModeFreeObjectProperties(props);
838 goto err;
839 }
840
Daniel Stone2ba17f42015-05-19 20:02:41 +0100841 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100842 }
Daniel Stone2ba17f42015-05-19 20:02:41 +0100843 else {
844 plane->possible_crtcs = (1 << output->pipe);
845 plane->plane_id = 0;
846 plane->count_formats = 1;
Sergi Granellf4456222017-01-12 17:17:32 +0000847 plane->formats[0].format = format;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100848 plane->type = type;
849 }
850
851 if (plane->type == WDRM_PLANE_TYPE__COUNT)
852 goto err_props;
853
854 /* With universal planes, everything is a DRM plane; without
855 * universal planes, the only DRM planes are overlay planes.
856 * Everything else is a fake plane. */
857 if (b->universal_planes) {
858 assert(kplane);
859 } else {
860 if (kplane)
861 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
862 else
863 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
864 output);
865 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100866
Pekka Paalanenec272712014-06-05 11:22:25 +0300867 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +0100868 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +0300869
870 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100871
872err_props:
873 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
874err:
875 drm_plane_state_free(plane->state_cur, true);
876 free(plane);
877 return NULL;
878}
879
880/**
881 * Find, or create, a special-purpose plane
882 *
883 * Primary and cursor planes are a special case, in that before universal
884 * planes, they are driven by non-plane API calls. Without universal plane
885 * support, the only way to configure a primary plane is via drmModeSetCrtc,
886 * and the only way to configure a cursor plane is drmModeSetCursor2.
887 *
888 * Although they may actually be regular planes in the hardware, without
889 * universal plane support, these planes are not actually exposed to
890 * userspace in the regular plane list.
891 *
892 * However, for ease of internal tracking, we want to manage all planes
893 * through the same drm_plane structures. Therefore, when we are running
894 * without universal plane support, we create fake drm_plane structures
895 * to track these planes.
896 *
897 * @param b DRM backend
898 * @param output Output to use for plane
899 * @param type Type of plane
900 */
901static struct drm_plane *
902drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
903 enum wdrm_plane_type type)
904{
905 struct drm_plane *plane;
906
907 if (!b->universal_planes) {
908 uint32_t format;
909
910 switch (type) {
911 case WDRM_PLANE_TYPE_CURSOR:
Stefan Agner0bfebeb2019-07-08 00:30:44 +0200912 format = DRM_FORMAT_ARGB8888;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100913 break;
Daniel Stonee2e80132018-01-16 15:37:33 +0000914 case WDRM_PLANE_TYPE_PRIMARY:
915 /* We don't know what formats the primary plane supports
916 * before universal planes, so we just assume that the
917 * GBM format works; however, this isn't set until after
918 * the output is created. */
919 format = 0;
920 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100921 default:
922 assert(!"invalid type in drm_output_find_special_plane");
923 break;
924 }
925
926 return drm_plane_create(b, NULL, output, type, format);
927 }
928
929 wl_list_for_each(plane, &b->plane_list, link) {
930 struct drm_output *tmp;
931 bool found_elsewhere = false;
932
933 if (plane->type != type)
934 continue;
935 if (!drm_plane_is_available(plane, output))
936 continue;
937
938 /* On some platforms, primary/cursor planes can roam
939 * between different CRTCs, so make sure we don't claim the
940 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +0100941 wl_list_for_each(tmp, &b->compositor->output_list,
942 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +0000943 if (tmp->cursor_plane == plane ||
944 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +0100945 found_elsewhere = true;
946 break;
947 }
948 }
949
950 if (found_elsewhere)
951 continue;
952
953 plane->possible_crtcs = (1 << output->pipe);
954 return plane;
955 }
956
957 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +0300958}
959
960/**
961 * Destroy one DRM plane
962 *
963 * Destroy a DRM plane, removing it from screen and releasing its retained
964 * buffers in the process. The counterpart to drm_plane_create.
965 *
966 * @param plane Plane to deallocate (will be freed)
967 */
968static void
969drm_plane_destroy(struct drm_plane *plane)
970{
Daniel Stone2ba17f42015-05-19 20:02:41 +0100971 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
972 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
973 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +0000974 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100975 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +0300976 weston_plane_release(&plane->base);
977 wl_list_remove(&plane->link);
978 free(plane);
979}
980
981/**
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900982 * Create a drm_plane for virtual output
983 *
984 * Call drm_virtual_plane_destroy to clean up the plane.
985 *
986 * @param b DRM compositor backend
987 * @param output Output to create internal plane for
988 */
989static struct drm_plane *
990drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
991{
992 struct drm_plane *plane;
993
994 /* num of formats is one */
995 plane = zalloc(sizeof(*plane) + sizeof(plane->formats[0]));
996 if (!plane) {
997 weston_log("%s: out of memory\n", __func__);
998 return NULL;
999 }
1000
1001 plane->type = WDRM_PLANE_TYPE_PRIMARY;
1002 plane->backend = b;
1003 plane->state_cur = drm_plane_state_alloc(NULL, plane);
1004 plane->state_cur->complete = true;
1005 plane->formats[0].format = output->gbm_format;
1006 plane->count_formats = 1;
Scott Anderson99553752019-01-28 15:40:55 +13001007 if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && b->fb_modifiers) {
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001008 uint64_t *modifiers = zalloc(sizeof *modifiers);
1009 if (modifiers) {
1010 *modifiers = DRM_FORMAT_MOD_LINEAR;
1011 plane->formats[0].modifiers = modifiers;
1012 plane->formats[0].count_modifiers = 1;
1013 }
1014 }
1015
1016 weston_plane_init(&plane->base, b->compositor, 0, 0);
1017 wl_list_insert(&b->plane_list, &plane->link);
1018
1019 return plane;
1020}
1021
1022/**
1023 * Destroy one DRM plane
1024 *
1025 * @param plane Plane to deallocate (will be freed)
1026 */
1027static void
1028drm_virtual_plane_destroy(struct drm_plane *plane)
1029{
1030 drm_plane_state_free(plane->state_cur, true);
1031 weston_plane_release(&plane->base);
1032 wl_list_remove(&plane->link);
1033 if (plane->formats[0].modifiers)
1034 free(plane->formats[0].modifiers);
1035 free(plane);
1036}
1037
1038/**
Pekka Paalanenec272712014-06-05 11:22:25 +03001039 * Initialise sprites (overlay planes)
1040 *
1041 * Walk the list of provided DRM planes, and add overlay planes.
1042 *
1043 * Call destroy_sprites to free these planes.
1044 *
1045 * @param b DRM compositor backend
1046 */
1047static void
1048create_sprites(struct drm_backend *b)
1049{
1050 drmModePlaneRes *kplane_res;
1051 drmModePlane *kplane;
1052 struct drm_plane *drm_plane;
1053 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +03001054 kplane_res = drmModeGetPlaneResources(b->drm.fd);
1055 if (!kplane_res) {
1056 weston_log("failed to get plane resources: %s\n",
1057 strerror(errno));
1058 return;
1059 }
1060
1061 for (i = 0; i < kplane_res->count_planes; i++) {
1062 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
1063 if (!kplane)
1064 continue;
1065
Daniel Stone2ba17f42015-05-19 20:02:41 +01001066 drm_plane = drm_plane_create(b, kplane, NULL,
1067 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +03001068 drmModeFreePlane(kplane);
1069 if (!drm_plane)
1070 continue;
1071
Daniel Stone085d2b92015-05-21 00:00:57 +01001072 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
1073 weston_compositor_stack_plane(b->compositor,
1074 &drm_plane->base,
1075 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +03001076 }
1077
1078 drmModeFreePlaneResources(kplane_res);
1079}
1080
1081/**
1082 * Clean up sprites (overlay planes)
1083 *
1084 * The counterpart to create_sprites.
1085 *
1086 * @param b DRM compositor backend
1087 */
1088static void
1089destroy_sprites(struct drm_backend *b)
1090{
1091 struct drm_plane *plane, *next;
1092
Daniel Stone085d2b92015-05-21 00:00:57 +01001093 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03001094 drm_plane_destroy(plane);
1095}
1096
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001097/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001098static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03001099drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001100{
1101 long brightness, max_brightness, norm;
1102
Pekka Paalanence724242017-09-04 12:21:24 +03001103 brightness = backlight_get_brightness(head->backlight);
1104 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001105
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001106 /* convert it on a scale of 0 to 255 */
1107 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001108
1109 return (uint32_t) norm;
1110}
1111
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001112/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001113static void
1114drm_set_backlight(struct weston_output *output_base, uint32_t value)
1115{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001116 struct drm_output *output = to_drm_output(output_base);
1117 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001118 long max_brightness, new_brightness;
1119
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001120 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001121 return;
1122
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001123 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1124 if (!head->backlight)
1125 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001126
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001127 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001128
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001129 /* get denormalized value */
1130 new_brightness = (value * max_brightness) / 255;
1131
1132 backlight_set_brightness(head->backlight, new_brightness);
1133 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001134}
1135
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001136static void
1137drm_output_init_backlight(struct drm_output *output)
1138{
1139 struct weston_head *base;
1140 struct drm_head *head;
1141
1142 output->base.set_backlight = NULL;
1143
1144 wl_list_for_each(base, &output->base.head_list, output_link) {
1145 head = to_drm_head(base);
1146
1147 if (head->backlight) {
1148 weston_log("Initialized backlight for head '%s', device %s\n",
1149 head->base.name, head->backlight->path);
1150
1151 if (!output->base.set_backlight) {
1152 output->base.set_backlight = drm_set_backlight;
1153 output->base.backlight_current =
1154 drm_get_backlight(head);
1155 }
1156 }
1157 }
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001158}
1159
Daniel Stonea08512f2016-11-08 17:46:10 +00001160/**
1161 * Power output on or off
1162 *
1163 * The DPMS/power level of an output is used to switch it on or off. This
1164 * is DRM's hook for doing so, which can called either as part of repaint,
1165 * or independently of the repaint loop.
1166 *
1167 * If we are called as part of repaint, we simply set the relevant bit in
1168 * state and return.
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001169 *
1170 * This function is never called on a virtual output.
Daniel Stonea08512f2016-11-08 17:46:10 +00001171 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001172static void
1173drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1174{
Armin Krezović545dba62016-08-05 15:54:18 +02001175 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00001176 struct drm_backend *b = to_drm_backend(output_base->compositor);
1177 struct drm_pending_state *pending_state = b->repaint_data;
1178 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01001179 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001180
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001181 assert(!output->virtual);
1182
Daniel Stonea08512f2016-11-08 17:46:10 +00001183 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001184 return;
1185
Daniel Stonea08512f2016-11-08 17:46:10 +00001186 /* If we're being called during the repaint loop, then this is
1187 * simple: discard any previously-generated state, and create a new
1188 * state where we disable everything. When we come to flush, this
1189 * will be applied.
1190 *
1191 * However, we need to be careful: we can be called whilst another
1192 * output is in its repaint cycle (pending_state exists), but our
1193 * output still has an incomplete state application outstanding.
1194 * In that case, we need to wait until that completes. */
1195 if (pending_state && !output->state_last) {
1196 /* The repaint loop already sets DPMS on; we don't need to
1197 * explicitly set it on here, as it will already happen
1198 * whilst applying the repaint state. */
1199 if (level == WESTON_DPMS_ON)
1200 return;
1201
1202 state = drm_pending_state_get_output(pending_state, output);
1203 if (state)
1204 drm_output_state_free(state);
1205 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01001206 return;
1207 }
1208
Daniel Stonea08512f2016-11-08 17:46:10 +00001209 /* As we throw everything away when disabling, just send us back through
1210 * a repaint cycle. */
1211 if (level == WESTON_DPMS_ON) {
1212 if (output->dpms_off_pending)
1213 output->dpms_off_pending = 0;
1214 weston_output_schedule_repaint(output_base);
1215 return;
1216 }
1217
1218 /* If we've already got a request in the pipeline, then we need to
1219 * park our DPMS request until that request has quiesced. */
1220 if (output->state_last) {
1221 output->dpms_off_pending = 1;
1222 return;
1223 }
1224
1225 pending_state = drm_pending_state_alloc(b);
1226 drm_output_get_disable_state(pending_state, output);
1227 ret = drm_pending_state_apply_sync(pending_state);
1228 if (ret != 0)
1229 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001230}
1231
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001232static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001233 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
1234 [DRM_MODE_CONNECTOR_VGA] = "VGA",
1235 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
1236 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
1237 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
1238 [DRM_MODE_CONNECTOR_Composite] = "Composite",
1239 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
1240 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
1241 [DRM_MODE_CONNECTOR_Component] = "Component",
1242 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
1243 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
1244 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
1245 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
1246 [DRM_MODE_CONNECTOR_TV] = "TV",
1247 [DRM_MODE_CONNECTOR_eDP] = "eDP",
Pekka Paalanenab81f152015-08-24 14:27:07 +03001248#ifdef DRM_MODE_CONNECTOR_DSI
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001249 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
1250 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Pekka Paalanenab81f152015-08-24 14:27:07 +03001251#endif
Stefan Agner30e283d2018-08-20 17:11:38 +02001252#ifdef DRM_MODE_CONNECTOR_DPI
1253 [DRM_MODE_CONNECTOR_DPI] = "DPI",
1254#endif
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001255};
1256
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001257/** Create a name given a DRM connector
1258 *
1259 * \param con The DRM connector whose type and id form the name.
1260 * \return A newly allocate string, or NULL on error. Must be free()'d
1261 * after use.
1262 *
1263 * The name does not identify the DRM display device.
1264 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001265static char *
1266make_connector_name(const drmModeConnector *con)
1267{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001268 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001269 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001270 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001271
1272 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1273 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001274
1275 if (!type_name)
1276 type_name = "UNNAMED";
1277
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001278 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
1279 if (ret < 0)
1280 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001281
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001282 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001283}
1284
Daniel Stonee4256832017-04-04 17:54:27 +01001285static void drm_output_fini_cursor_egl(struct drm_output *output)
1286{
1287 unsigned int i;
1288
1289 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
1290 drm_fb_unref(output->gbm_cursor_fb[i]);
1291 output->gbm_cursor_fb[i] = NULL;
1292 }
1293}
1294
1295static int
1296drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
1297{
1298 unsigned int i;
1299
Daniel Stone2ba17f42015-05-19 20:02:41 +01001300 /* No point creating cursors if we don't have a plane for them. */
1301 if (!output->cursor_plane)
1302 return 0;
1303
Daniel Stonee4256832017-04-04 17:54:27 +01001304 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
1305 struct gbm_bo *bo;
1306
1307 bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
1308 GBM_FORMAT_ARGB8888,
1309 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
1310 if (!bo)
1311 goto err;
1312
1313 output->gbm_cursor_fb[i] =
Daniel Stonedb10df12016-12-08 13:15:58 +00001314 drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR);
Daniel Stonee4256832017-04-04 17:54:27 +01001315 if (!output->gbm_cursor_fb[i]) {
1316 gbm_bo_destroy(bo);
1317 goto err;
1318 }
Stefan Agner974390a2019-07-08 00:42:05 +02001319 output->gbm_cursor_handle[i] = gbm_bo_get_handle(bo).s32;
Daniel Stonee4256832017-04-04 17:54:27 +01001320 }
1321
1322 return 0;
1323
1324err:
1325 weston_log("cursor buffers unavailable, using gl cursors\n");
1326 b->cursors_are_broken = 1;
1327 drm_output_fini_cursor_egl(output);
1328 return -1;
1329}
1330
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001331/* Init output state that depends on gl or gbm */
1332static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001333drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001334{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001335 EGLint format[2] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001336 output->gbm_format,
1337 fallback_format_for(output->gbm_format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05001338 };
Daniel Stonee4256832017-04-04 17:54:27 +01001339 int n_formats = 1;
Daniel Stone244244d2016-11-18 18:02:08 +00001340 struct weston_mode *mode = output->base.current_mode;
1341 struct drm_plane *plane = output->scanout_plane;
1342 unsigned int i;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001343
Philipp Zabel5c8eef12019-03-06 11:12:47 +01001344 assert(output->gbm_surface == NULL);
1345
Daniel Stone244244d2016-11-18 18:02:08 +00001346 for (i = 0; i < plane->count_formats; i++) {
1347 if (plane->formats[i].format == output->gbm_format)
1348 break;
1349 }
1350
1351 if (i == plane->count_formats) {
1352 weston_log("format 0x%x not supported by output %s\n",
1353 output->gbm_format, output->base.name);
1354 return -1;
1355 }
1356
1357#ifdef HAVE_GBM_MODIFIERS
1358 if (plane->formats[i].count_modifiers > 0) {
1359 output->gbm_surface =
1360 gbm_surface_create_with_modifiers(b->gbm,
1361 mode->width,
1362 mode->height,
1363 output->gbm_format,
1364 plane->formats[i].modifiers,
1365 plane->formats[i].count_modifiers);
Daniel Stoneee1d9682019-01-31 00:02:25 +00001366 }
1367
1368 /* If allocating with modifiers fails, try again without. This can
1369 * happen when the KMS display device supports modifiers but the
1370 * GBM driver does not, e.g. the old i915 Mesa driver. */
1371 if (!output->gbm_surface)
Daniel Stone244244d2016-11-18 18:02:08 +00001372#endif
1373 {
1374 output->gbm_surface =
1375 gbm_surface_create(b->gbm, mode->width, mode->height,
1376 output->gbm_format,
Tomohito Esaki718a40b2018-01-31 17:50:15 +09001377 output->gbm_bo_flags);
Daniel Stone244244d2016-11-18 18:02:08 +00001378 }
1379
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001380 if (!output->gbm_surface) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001381 weston_log("failed to create gbm surface\n");
1382 return -1;
1383 }
1384
Derek Foremanc4cfe852015-05-15 12:12:40 -05001385 if (format[1])
1386 n_formats = 2;
Miguel A. Vicoc095cde2016-05-18 17:43:00 +02001387 if (gl_renderer->output_window_create(&output->base,
1388 (EGLNativeWindowType)output->gbm_surface,
1389 output->gbm_surface,
1390 gl_renderer->opaque_attribs,
1391 format,
1392 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001393 weston_log("failed to create gl renderer output state\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001394 gbm_surface_destroy(output->gbm_surface);
Philipp Zabel5c8eef12019-03-06 11:12:47 +01001395 output->gbm_surface = NULL;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001396 return -1;
1397 }
1398
Daniel Stonee4256832017-04-04 17:54:27 +01001399 drm_output_init_cursor_egl(output, b);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001400
1401 return 0;
1402}
1403
Daniel Stone3e661f72016-11-04 17:24:06 +00001404static void
1405drm_output_fini_egl(struct drm_output *output)
1406{
Daniel Stonee2e80132018-01-16 15:37:33 +00001407 struct drm_backend *b = to_drm_backend(output->base.compositor);
1408
1409 /* Destroying the GBM surface will destroy all our GBM buffers,
1410 * regardless of refcount. Ensure we destroy them here. */
1411 if (!b->shutting_down &&
1412 output->scanout_plane->state_cur->fb &&
1413 output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
1414 drm_plane_state_free(output->scanout_plane->state_cur, true);
1415 output->scanout_plane->state_cur =
1416 drm_plane_state_alloc(NULL, output->scanout_plane);
1417 output->scanout_plane->state_cur->complete = true;
1418 }
1419
Daniel Stone3e661f72016-11-04 17:24:06 +00001420 gl_renderer->output_destroy(&output->base);
1421 gbm_surface_destroy(output->gbm_surface);
Philipp Zabel5c8eef12019-03-06 11:12:47 +01001422 output->gbm_surface = NULL;
Daniel Stonee4256832017-04-04 17:54:27 +01001423 drm_output_fini_cursor_egl(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00001424}
1425
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001426static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001427drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001428{
Hardeningff39efa2013-09-18 23:56:35 +02001429 int w = output->base.current_mode->width;
1430 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001431 uint32_t format = output->gbm_format;
1432 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001433 unsigned int i;
Pekka Paalanendee412d2018-04-23 11:44:58 +02001434 uint32_t flags = 0;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001435
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001436 switch (format) {
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001437 case DRM_FORMAT_XRGB8888:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001438 pixman_format = PIXMAN_x8r8g8b8;
1439 break;
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001440 case DRM_FORMAT_RGB565:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001441 pixman_format = PIXMAN_r5g6b5;
1442 break;
1443 default:
1444 weston_log("Unsupported pixman format 0x%x\n", format);
1445 return -1;
1446 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001447
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001448 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001449 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001450 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001451 if (!output->dumb[i])
1452 goto err;
1453
1454 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001455 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001456 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00001457 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001458 if (!output->image[i])
1459 goto err;
1460 }
1461
Pekka Paalanendee412d2018-04-23 11:44:58 +02001462 if (b->use_pixman_shadow)
1463 flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
1464
1465 if (pixman_renderer_output_create(&output->base, flags) < 0)
1466 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05301467
Pekka Paalanendee412d2018-04-23 11:44:58 +02001468 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
1469 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001470
1471 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001472 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001473
1474 return 0;
1475
1476err:
1477 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1478 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01001479 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001480 if (output->image[i])
1481 pixman_image_unref(output->image[i]);
1482
1483 output->dumb[i] = NULL;
1484 output->image[i] = NULL;
1485 }
1486
1487 return -1;
1488}
1489
1490static void
1491drm_output_fini_pixman(struct drm_output *output)
1492{
Daniel Stonee2e80132018-01-16 15:37:33 +00001493 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001494 unsigned int i;
1495
Daniel Stonee2e80132018-01-16 15:37:33 +00001496 /* Destroying the Pixman surface will destroy all our buffers,
1497 * regardless of refcount. Ensure we destroy them here. */
1498 if (!b->shutting_down &&
1499 output->scanout_plane->state_cur->fb &&
1500 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
1501 drm_plane_state_free(output->scanout_plane->state_cur, true);
1502 output->scanout_plane->state_cur =
1503 drm_plane_state_alloc(NULL, output->scanout_plane);
1504 output->scanout_plane->state_cur->complete = true;
1505 }
1506
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001507 pixman_renderer_output_destroy(&output->base);
1508 pixman_region32_fini(&output->previous_damage);
1509
1510 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001511 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001512 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001513 output->dumb[i] = NULL;
1514 output->image[i] = NULL;
1515 }
1516}
1517
Richard Hughes2b2092a2013-04-24 14:58:02 +01001518static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001519setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01001520 struct weston_output *output,
1521 const char *s)
1522{
1523 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05001524 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001525 struct udev_seat *seat;
1526
Giulio Camuffo954f1832014-10-11 18:27:30 +03001527 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05001528 if (!seat)
1529 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001530
Derek Foreman0720ea32015-07-15 13:00:35 -05001531 seat->base.output = output;
1532
Derek Foreman1281a362015-07-31 16:55:32 -05001533 pointer = weston_seat_get_pointer(&seat->base);
1534 if (pointer)
1535 weston_pointer_clamp(pointer,
1536 &pointer->x,
1537 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001538 }
1539}
1540
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001541static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03001542drm_output_attach_head(struct weston_output *output_base,
1543 struct weston_head *head_base)
1544{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001545 struct drm_backend *b = to_drm_backend(output_base->compositor);
1546
Pekka Paalanenc112f002017-08-28 16:27:20 +03001547 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
1548 return -1;
1549
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001550 if (!output_base->enabled)
1551 return 0;
1552
1553 /* XXX: ensure the configuration will work.
1554 * This is actually impossible without major infrastructure
1555 * work. */
1556
1557 /* Need to go through modeset to add connectors. */
1558 /* XXX: Ideally we'd do this per-output, not globally. */
1559 /* XXX: Doing it globally, what guarantees another output's update
1560 * will not clear the flag before this output is updated?
1561 */
1562 b->state_invalid = true;
1563
1564 weston_output_schedule_repaint(output_base);
1565
Pekka Paalanenc112f002017-08-28 16:27:20 +03001566 return 0;
1567}
1568
Pekka Paalanen7f853792017-11-29 14:33:33 +02001569static void
1570drm_output_detach_head(struct weston_output *output_base,
1571 struct weston_head *head_base)
1572{
1573 struct drm_backend *b = to_drm_backend(output_base->compositor);
1574
1575 if (!output_base->enabled)
1576 return;
1577
1578 /* Need to go through modeset to drop connectors that should no longer
1579 * be driven. */
1580 /* XXX: Ideally we'd do this per-output, not globally. */
1581 b->state_invalid = true;
1582
1583 weston_output_schedule_repaint(output_base);
1584}
1585
Pekka Paalanenc112f002017-08-28 16:27:20 +03001586static int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001587parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001588{
Pekka Paalanen62a94362018-09-26 14:33:36 +03001589 const struct pixel_format_info *pinfo;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001590
Pekka Paalanen62a94362018-09-26 14:33:36 +03001591 if (s == NULL) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001592 *gbm_format = default_value;
Pekka Paalanen62a94362018-09-26 14:33:36 +03001593
1594 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001595 }
1596
Pekka Paalanen62a94362018-09-26 14:33:36 +03001597 pinfo = pixel_format_get_info_by_drm_name(s);
1598 if (!pinfo) {
1599 weston_log("fatal: unrecognized pixel format: %s\n", s);
1600
1601 return -1;
1602 }
1603
1604 /* GBM formats and DRM formats are identical. */
1605 *gbm_format = pinfo->format;
1606
1607 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001608}
1609
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001610static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001611drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001612{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001613 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001614 drmModeEncoder *encoder;
1615 drmModeCrtc *crtc;
1616
1617 /* Get the current mode on the crtc that's currently driving
1618 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001619 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001620 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001621 head->inherited_crtc_id = encoder->crtc_id;
1622
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001623 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
1624 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001625
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001626 if (crtc == NULL)
1627 return -1;
1628 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02001629 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001630 drmModeFreeCrtc(crtc);
1631 }
1632
1633 return 0;
1634}
1635
Armin Krezović08368132016-09-30 14:11:05 +02001636static void
1637drm_output_set_gbm_format(struct weston_output *base,
1638 const char *gbm_format)
1639{
1640 struct drm_output *output = to_drm_output(base);
1641 struct drm_backend *b = to_drm_backend(base->compositor);
1642
1643 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
1644 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00001645
1646 /* Without universal planes, we can't discover which formats are
1647 * supported by the primary plane; we just hope that the GBM format
1648 * works. */
1649 if (!b->universal_planes)
Sergi Granellf4456222017-01-12 17:17:32 +00001650 output->scanout_plane->formats[0].format = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02001651}
1652
1653static void
1654drm_output_set_seat(struct weston_output *base,
1655 const char *seat)
1656{
1657 struct drm_output *output = to_drm_output(base);
1658 struct drm_backend *b = to_drm_backend(base->compositor);
1659
1660 setup_output_seat_constraint(b, &output->base,
1661 seat ? seat : "");
1662}
1663
1664static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001665drm_output_init_gamma_size(struct drm_output *output)
1666{
1667 struct drm_backend *backend = to_drm_backend(output->base.compositor);
1668 drmModeCrtc *crtc;
1669
1670 assert(output->base.compositor);
1671 assert(output->crtc_id != 0);
1672 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
1673 if (!crtc)
1674 return -1;
1675
1676 output->base.gamma_size = crtc->gamma_size;
1677
1678 drmModeFreeCrtc(crtc);
1679
1680 return 0;
1681}
1682
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001683static uint32_t
1684drm_head_get_possible_crtcs_mask(struct drm_head *head)
1685{
1686 uint32_t possible_crtcs = 0;
1687 drmModeEncoder *encoder;
1688 int i;
1689
1690 for (i = 0; i < head->connector->count_encoders; i++) {
1691 encoder = drmModeGetEncoder(head->backend->drm.fd,
1692 head->connector->encoders[i]);
1693 if (!encoder)
1694 continue;
1695
1696 possible_crtcs |= encoder->possible_crtcs;
1697 drmModeFreeEncoder(encoder);
1698 }
1699
1700 return possible_crtcs;
1701}
1702
1703static int
1704drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
1705{
1706 int i;
1707
1708 for (i = 0; i < resources->count_crtcs; i++) {
1709 if (resources->crtcs[i] == crtc_id)
1710 return i;
1711 }
1712
1713 assert(0 && "unknown crtc id");
1714 return -1;
1715}
1716
1717/** Pick a CRTC that might be able to drive all attached connectors
1718 *
1719 * @param output The output whose attached heads to include.
1720 * @param resources The DRM KMS resources.
1721 * @return CRTC index, or -1 on failure or not found.
1722 */
1723static int
1724drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
1725{
1726 struct drm_backend *backend;
1727 struct weston_head *base;
1728 struct drm_head *head;
1729 uint32_t possible_crtcs = 0xffffffff;
1730 int existing_crtc[32];
1731 unsigned j, n = 0;
1732 uint32_t crtc_id;
1733 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001734 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001735 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001736 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001737
1738 backend = to_drm_backend(output->base.compositor);
1739
1740 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
1741 * because it is more often set wrong than not in the kernel. */
1742
1743 /* Accumulate a mask of possible crtcs and find existing routings. */
1744 wl_list_for_each(base, &output->base.head_list, output_link) {
1745 head = to_drm_head(base);
1746
1747 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
1748
1749 crtc_id = head->inherited_crtc_id;
1750 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
1751 existing_crtc[n++] = drm_crtc_get_index(resources,
1752 crtc_id);
1753 }
1754
1755 /* Find a crtc that could drive each connector individually at least,
1756 * and prefer existing routings. */
1757 for (i = 0; i < resources->count_crtcs; i++) {
1758 crtc_id = resources->crtcs[i];
1759
1760 /* Could the crtc not drive each connector? */
1761 if (!(possible_crtcs & (1 << i)))
1762 continue;
1763
1764 /* Is the crtc already in use? */
1765 if (drm_output_find_by_crtc(backend, crtc_id))
1766 continue;
1767
1768 /* Try to preserve the existing CRTC -> connector routing;
1769 * it makes initialisation faster, and also since we have a
1770 * very dumb picking algorithm, may preserve a better
1771 * choice. */
1772 for (j = 0; j < n; j++) {
1773 if (existing_crtc[j] == i)
1774 return i;
1775 }
1776
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001777 /* Check if any other head had existing routing to this CRTC.
1778 * If they did, this is not the best CRTC as it might be needed
1779 * for another output we haven't enabled yet. */
1780 match = false;
1781 wl_list_for_each(base, &backend->compositor->head_list,
1782 compositor_link) {
1783 head = to_drm_head(base);
1784
1785 if (head->base.output == &output->base)
1786 continue;
1787
1788 if (weston_head_is_enabled(&head->base))
1789 continue;
1790
1791 if (head->inherited_crtc_id == crtc_id) {
1792 match = true;
1793 break;
1794 }
1795 }
1796 if (!match)
1797 best_crtc_index = i;
1798
1799 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001800 }
1801
1802 if (best_crtc_index != -1)
1803 return best_crtc_index;
1804
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001805 if (fallback_crtc_index != -1)
1806 return fallback_crtc_index;
1807
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001808 /* Likely possible_crtcs was empty due to asking for clones,
1809 * but since the DRM documentation says the kernel lies, let's
1810 * pick one crtc anyway. Trial and error is the only way to
1811 * be sure if something doesn't work. */
1812
1813 /* First pick any existing assignment. */
1814 for (j = 0; j < n; j++) {
1815 crtc_id = resources->crtcs[existing_crtc[j]];
1816 if (!drm_output_find_by_crtc(backend, crtc_id))
1817 return existing_crtc[j];
1818 }
1819
1820 /* Otherwise pick any available crtc. */
1821 for (i = 0; i < resources->count_crtcs; i++) {
1822 crtc_id = resources->crtcs[i];
1823
1824 if (!drm_output_find_by_crtc(backend, crtc_id))
1825 return i;
1826 }
1827
1828 return -1;
1829}
1830
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001831/** Allocate a CRTC for the output
1832 *
1833 * @param output The output with no allocated CRTC.
1834 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001835 * @return 0 on success, -1 on failure.
1836 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001837 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001838 * for the output, and loads the CRTC properties.
1839 *
1840 * Populates the cursor and scanout planes.
1841 *
1842 * On failure, the output remains without a CRTC.
1843 */
1844static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001845drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001846{
1847 struct drm_backend *b = to_drm_backend(output->base.compositor);
1848 drmModeObjectPropertiesPtr props;
1849 int i;
1850
1851 assert(output->crtc_id == 0);
1852
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001853 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001854 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001855 weston_log("Output '%s': No available CRTCs.\n",
1856 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001857 return -1;
1858 }
1859
1860 output->crtc_id = resources->crtcs[i];
1861 output->pipe = i;
1862
1863 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
1864 DRM_MODE_OBJECT_CRTC);
1865 if (!props) {
1866 weston_log("failed to get CRTC properties\n");
1867 goto err_crtc;
1868 }
1869 drm_property_info_populate(b, crtc_props, output->props_crtc,
1870 WDRM_CRTC__COUNT, props);
1871 drmModeFreeObjectProperties(props);
1872
1873 output->scanout_plane =
1874 drm_output_find_special_plane(b, output,
1875 WDRM_PLANE_TYPE_PRIMARY);
1876 if (!output->scanout_plane) {
1877 weston_log("Failed to find primary plane for output %s\n",
1878 output->base.name);
1879 goto err_crtc;
1880 }
1881
1882 /* Failing to find a cursor plane is not fatal, as we'll fall back
1883 * to software cursor. */
1884 output->cursor_plane =
1885 drm_output_find_special_plane(b, output,
1886 WDRM_PLANE_TYPE_CURSOR);
1887
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001888 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
1889
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001890 return 0;
1891
1892err_crtc:
1893 output->crtc_id = 0;
1894 output->pipe = 0;
1895
1896 return -1;
1897}
1898
1899/** Free the CRTC from the output
1900 *
1901 * @param output The output whose CRTC to deallocate.
1902 *
1903 * The CRTC reserved for the given output becomes free to use again.
1904 */
1905static void
1906drm_output_fini_crtc(struct drm_output *output)
1907{
1908 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001909 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001910
1911 if (!b->universal_planes && !b->shutting_down) {
1912 /* With universal planes, the 'special' planes are allocated at
1913 * startup, freed at shutdown, and live on the plane list in
1914 * between. We want the planes to continue to exist and be freed
1915 * up for other outputs.
1916 *
1917 * Without universal planes, our special planes are
1918 * pseudo-planes allocated at output creation, freed at output
1919 * destruction, and not usable by other outputs.
1920 *
1921 * On the other hand, if the compositor is already shutting down,
1922 * the plane has already been destroyed.
1923 */
1924 if (output->cursor_plane)
1925 drm_plane_destroy(output->cursor_plane);
1926 if (output->scanout_plane)
1927 drm_plane_destroy(output->scanout_plane);
1928 }
1929
1930 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001931
1932 assert(output->crtc_id != 0);
1933
1934 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
1935 *unused = output->crtc_id;
1936
1937 /* Force resetting unused CRTCs */
1938 b->state_invalid = true;
1939
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001940 output->crtc_id = 0;
1941 output->cursor_plane = NULL;
1942 output->scanout_plane = NULL;
1943}
1944
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001945static int
Armin Krezović08368132016-09-30 14:11:05 +02001946drm_output_enable(struct weston_output *base)
1947{
1948 struct drm_output *output = to_drm_output(base);
1949 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001950 drmModeRes *resources;
1951 int ret;
1952
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001953 assert(!output->virtual);
1954
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001955 resources = drmModeGetResources(b->drm.fd);
1956 if (!resources) {
1957 weston_log("drmModeGetResources failed\n");
1958 return -1;
1959 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001960 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001961 drmModeFreeResources(resources);
1962 if (ret < 0)
1963 return -1;
1964
1965 if (drm_output_init_gamma_size(output) < 0)
1966 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02001967
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001968 if (b->pageflip_timeout)
1969 drm_output_pageflip_timer_create(output);
1970
Giulio Camuffo954f1832014-10-11 18:27:30 +03001971 if (b->use_pixman) {
1972 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001973 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00001974 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001975 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03001976 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001977 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00001978 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001979 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001980
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001981 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001982
Jonas Ådahle5a12252013-04-05 23:07:11 +02001983 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001984 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001985 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001986 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001987 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01001988 output->base.set_gamma = drm_output_set_gamma;
1989
Daniel Stone2ba17f42015-05-19 20:02:41 +01001990 if (output->cursor_plane)
1991 weston_compositor_stack_plane(b->compositor,
1992 &output->cursor_plane->base,
1993 NULL);
1994 else
1995 b->cursors_are_broken = 1;
1996
Daniel Stonee2e80132018-01-16 15:37:33 +00001997 weston_compositor_stack_plane(b->compositor,
1998 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001999 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002000
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02002001 weston_log("Output %s (crtc %d) video modes:\n",
2002 output->base.name, output->crtc_id);
2003 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002004
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002005 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002006
Daniel Stone02cf4662017-03-03 16:19:39 +00002007err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03002008 drm_output_fini_crtc(output);
2009
David Herrmann0f0d54e2011-12-08 17:05:45 +01002010 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002011}
2012
Jesse Barnes58ef3792012-02-23 09:45:49 -05002013static void
Armin Krezović08368132016-09-30 14:11:05 +02002014drm_output_deinit(struct weston_output *base)
2015{
2016 struct drm_output *output = to_drm_output(base);
2017 struct drm_backend *b = to_drm_backend(base->compositor);
2018
Daniel Stone3e661f72016-11-04 17:24:06 +00002019 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02002020 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00002021 else
2022 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02002023
Daniel Stone2ba17f42015-05-19 20:02:41 +01002024 /* Since our planes are no longer in use anywhere, remove their base
2025 * weston_plane's link from the plane stacking list, unless we're
2026 * shutting down, in which case the plane has already been
2027 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00002028 if (!b->shutting_down) {
2029 wl_list_remove(&output->scanout_plane->base.link);
2030 wl_list_init(&output->scanout_plane->base.link);
2031
2032 if (output->cursor_plane) {
2033 wl_list_remove(&output->cursor_plane->base.link);
2034 wl_list_init(&output->cursor_plane->base.link);
2035 /* Turn off hardware cursor */
2036 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
2037 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01002038 }
Daniel Stone087ddf02017-02-14 17:51:30 +00002039
Pekka Paalanen663d5e92017-09-08 13:32:40 +03002040 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02002041}
2042
2043static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03002044drm_head_destroy(struct drm_head *head);
2045
2046static void
Armin Krezović08368132016-09-30 14:11:05 +02002047drm_output_destroy(struct weston_output *base)
2048{
2049 struct drm_output *output = to_drm_output(base);
2050 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02002051
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002052 assert(!output->virtual);
2053
Daniel Stone31838bf2019-06-17 11:23:25 +01002054 if (output->page_flip_pending || output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02002055 output->destroy_pending = 1;
2056 weston_log("destroy output while page flip pending\n");
2057 return;
2058 }
2059
2060 if (output->base.enabled)
2061 drm_output_deinit(&output->base);
2062
Pekka Paalanen383b3af2017-09-11 14:40:48 +03002063 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02002064
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002065 if (output->pageflip_timer)
2066 wl_event_source_remove(output->pageflip_timer);
2067
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03002068 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02002069
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002070 assert(!output->state_last);
2071 drm_output_state_free(output->state_cur);
2072
Armin Krezović08368132016-09-30 14:11:05 +02002073 free(output);
2074}
2075
2076static int
2077drm_output_disable(struct weston_output *base)
2078{
2079 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02002080
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002081 assert(!output->virtual);
2082
Daniel Stone31838bf2019-06-17 11:23:25 +01002083 if (output->page_flip_pending || output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02002084 output->disable_pending = 1;
2085 return -1;
2086 }
2087
Daniel Stonea08512f2016-11-08 17:46:10 +00002088 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00002089
Armin Krezović08368132016-09-30 14:11:05 +02002090 if (output->base.enabled)
2091 drm_output_deinit(&output->base);
2092
2093 output->disable_pending = 0;
2094
Armin Krezović08368132016-09-30 14:11:05 +02002095 return 0;
2096}
2097
2098/**
Daniel Stone087ddf02017-02-14 17:51:30 +00002099 * Update the list of unused connectors and CRTCs
2100 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03002101 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00002102 *
2103 * @param b Weston backend structure
2104 * @param resources DRM resources for this device
2105 */
2106static void
2107drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
2108{
2109 int i;
2110
Daniel Stone087ddf02017-02-14 17:51:30 +00002111 wl_array_release(&b->unused_crtcs);
2112 wl_array_init(&b->unused_crtcs);
2113
2114 for (i = 0; i < resources->count_crtcs; i++) {
2115 struct drm_output *output;
2116 uint32_t *crtc_id;
2117
2118 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
2119 if (output && output->base.enabled)
2120 continue;
2121
2122 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
2123 *crtc_id = resources->crtcs[i];
2124 }
2125}
2126
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002127/** Replace connector data and monitor information
2128 *
2129 * @param head The head to update.
2130 * @param connector The connector data to be owned by the head, must match
2131 * the head's connector ID.
2132 * @return 0 on success, -1 on failure.
2133 *
2134 * Takes ownership of @c connector on success, not on failure.
2135 *
2136 * May schedule a heads changed call.
2137 */
2138static int
2139drm_head_assign_connector_info(struct drm_head *head,
2140 drmModeConnector *connector)
2141{
2142 drmModeObjectProperties *props;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002143
2144 assert(connector);
2145 assert(head->connector_id == connector->connector_id);
2146
2147 props = drmModeObjectGetProperties(head->backend->drm.fd,
2148 head->connector_id,
2149 DRM_MODE_OBJECT_CONNECTOR);
2150 if (!props) {
2151 weston_log("Error: failed to get connector '%s' properties\n",
2152 head->base.name);
2153 return -1;
2154 }
2155
2156 if (head->connector)
2157 drmModeFreeConnector(head->connector);
2158 head->connector = connector;
2159
2160 drm_property_info_populate(head->backend, connector_props,
2161 head->props_conn,
2162 WDRM_CONNECTOR__COUNT, props);
Daniel Stone3448cfc2019-06-26 22:56:39 +01002163 update_head_from_connector(head, props);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002164 drmModeFreeObjectProperties(props);
2165
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002166 return 0;
2167}
2168
Pekka Paalanen456dc732017-11-09 15:10:11 +02002169static void
2170drm_head_log_info(struct drm_head *head, const char *msg)
2171{
2172 if (head->base.connected) {
2173 weston_log("DRM: head '%s' %s, connector %d is connected, "
2174 "EDID make '%s', model '%s', serial '%s'\n",
2175 head->base.name, msg, head->connector_id,
2176 head->base.make, head->base.model,
2177 head->base.serial_number ?: "");
2178 } else {
2179 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
2180 head->base.name, msg, head->connector_id);
2181 }
2182}
2183
Pekka Paalanend2e62422017-09-08 15:48:07 +03002184/** Update connector and monitor information
2185 *
2186 * @param head The head to update.
2187 *
2188 * Re-reads the DRM property lists for the connector and updates monitor
2189 * information and connection status. This may schedule a heads changed call
2190 * to the user.
2191 */
2192static void
2193drm_head_update_info(struct drm_head *head)
2194{
2195 drmModeConnector *connector;
2196
2197 connector = drmModeGetConnector(head->backend->drm.fd,
2198 head->connector_id);
2199 if (!connector) {
2200 weston_log("DRM: getting connector info for '%s' failed.\n",
2201 head->base.name);
2202 return;
2203 }
2204
2205 if (drm_head_assign_connector_info(head, connector) < 0)
2206 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002207
2208 if (head->base.device_changed)
2209 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03002210}
2211
Daniel Stone087ddf02017-02-14 17:51:30 +00002212/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03002213 * Create a Weston head for a connector
2214 *
2215 * Given a DRM connector, create a matching drm_head structure and add it
2216 * to Weston's head list.
2217 *
Marius Vlada2dace22019-06-12 16:05:44 +03002218 * @param backend Weston backend structure
Pekka Paalanenc112f002017-08-28 16:27:20 +03002219 * @param connector_id DRM connector ID for the head
2220 * @param drm_device udev device pointer
2221 * @returns The new head, or NULL on failure.
2222 */
2223static struct drm_head *
2224drm_head_create(struct drm_backend *backend, uint32_t connector_id,
2225 struct udev_device *drm_device)
2226{
2227 struct drm_head *head;
2228 drmModeConnector *connector;
2229 char *name;
2230
2231 head = zalloc(sizeof *head);
2232 if (!head)
2233 return NULL;
2234
2235 connector = drmModeGetConnector(backend->drm.fd, connector_id);
2236 if (!connector)
2237 goto err_alloc;
2238
2239 name = make_connector_name(connector);
2240 if (!name)
2241 goto err_alloc;
2242
2243 weston_head_init(&head->base, name);
2244 free(name);
2245
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002246 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002247 head->backend = backend;
2248
Pekka Paalanence724242017-09-04 12:21:24 +03002249 head->backlight = backlight_init(drm_device, connector->connector_type);
2250
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002251 if (drm_head_assign_connector_info(head, connector) < 0)
2252 goto err_init;
2253
2254 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
2255 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
2256 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002257
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02002258 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002259 weston_log("Failed to retrieve current mode from connector %d.\n",
2260 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02002261 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002262 }
2263
Pekka Paalanenc112f002017-08-28 16:27:20 +03002264 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002265 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03002266
2267 return head;
2268
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002269err_init:
2270 weston_head_release(&head->base);
2271
Pekka Paalanenc112f002017-08-28 16:27:20 +03002272err_alloc:
2273 if (connector)
2274 drmModeFreeConnector(connector);
2275
2276 free(head);
2277
2278 return NULL;
2279}
2280
2281static void
2282drm_head_destroy(struct drm_head *head)
2283{
2284 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03002285
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002286 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
2287 drmModeFreeConnector(head->connector);
2288
Pekka Paalanence724242017-09-04 12:21:24 +03002289 if (head->backlight)
2290 backlight_destroy(head->backlight);
2291
Pekka Paalanenc112f002017-08-28 16:27:20 +03002292 free(head);
2293}
2294
2295/**
Armin Krezović08368132016-09-30 14:11:05 +02002296 * Create a Weston output structure
2297 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002298 * Create an "empty" drm_output. This is the implementation of
2299 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02002300 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002301 * Creating an output is usually followed by drm_output_attach_head()
2302 * and drm_output_enable() to make use of it.
2303 *
2304 * @param compositor The compositor instance.
2305 * @param name Name for the new output.
2306 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02002307 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03002308static struct weston_output *
2309drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02002310{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002311 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02002312 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02002313
Armin Krezović08368132016-09-30 14:11:05 +02002314 output = zalloc(sizeof *output);
2315 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002316 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02002317
Daniel Stone64dbbee2018-07-20 19:00:06 +01002318 output->backend = b;
Tomohito Esaki718a40b2018-01-31 17:50:15 +09002319 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Daniel Stone64dbbee2018-07-20 19:00:06 +01002320
Pekka Paalanend2e62422017-09-08 15:48:07 +03002321 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002322
Armin Krezović08368132016-09-30 14:11:05 +02002323 output->base.enable = drm_output_enable;
2324 output->base.destroy = drm_output_destroy;
2325 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002326 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02002327 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02002328
2329 output->destroy_pending = 0;
2330 output->disable_pending = 0;
Armin Krezović08368132016-09-30 14:11:05 +02002331
Pekka Paalanen01f60212017-03-24 15:39:24 +02002332 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03002333
Armin Krezović08368132016-09-30 14:11:05 +02002334 weston_compositor_add_pending_output(&output->base, b->compositor);
2335
Pekka Paalanend2e62422017-09-08 15:48:07 +03002336 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02002337}
2338
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002339static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03002340drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002341{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002342 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002343 drmModeRes *resources;
2344 int i;
2345
Giulio Camuffo954f1832014-10-11 18:27:30 +03002346 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002347 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002348 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002349 return -1;
2350 }
2351
Giulio Camuffo954f1832014-10-11 18:27:30 +03002352 b->min_width = resources->min_width;
2353 b->max_width = resources->max_width;
2354 b->min_height = resources->min_height;
2355 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002356
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002357 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002358 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00002359
Pekka Paalanend2e62422017-09-08 15:48:07 +03002360 head = drm_head_create(b, connector_id, drm_device);
2361 if (!head) {
2362 weston_log("DRM: failed to create head for connector %d.\n",
2363 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002364 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002365 }
2366
Daniel Stone087ddf02017-02-14 17:51:30 +00002367 drm_backend_update_unused_outputs(b, resources);
2368
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002369 drmModeFreeResources(resources);
2370
2371 return 0;
2372}
2373
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002374static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03002375drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002376{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002377 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002378 struct weston_head *base, *next;
2379 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002380 int i;
2381
Giulio Camuffo954f1832014-10-11 18:27:30 +03002382 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002383 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002384 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002385 return;
2386 }
2387
Pekka Paalanend2e62422017-09-08 15:48:07 +03002388 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002389 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00002390 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02002391
Pekka Paalanend2e62422017-09-08 15:48:07 +03002392 head = drm_head_find_by_connector(b, connector_id);
2393 if (head) {
2394 drm_head_update_info(head);
2395 } else {
2396 head = drm_head_create(b, connector_id, drm_device);
2397 if (!head)
2398 weston_log("DRM: failed to create head for hot-added connector %d.\n",
2399 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002400 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002401 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002402
Pekka Paalanend2e62422017-09-08 15:48:07 +03002403 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03002404 wl_list_for_each_safe(base, next,
2405 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002406 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002407
Pekka Paalanena0a37462017-08-31 15:41:57 +03002408 head = to_drm_head(base);
2409
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002410 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002411 if (resources->connectors[i] == head->connector_id) {
2412 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002413 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002414 }
2415 }
Armin Krezović08368132016-09-30 14:11:05 +02002416
Pekka Paalanend2e62422017-09-08 15:48:07 +03002417 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002418 continue;
2419
Pekka Paalanend2e62422017-09-08 15:48:07 +03002420 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
2421 head->base.name, head->connector_id);
2422 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002423 }
2424
Daniel Stone087ddf02017-02-14 17:51:30 +00002425 drm_backend_update_unused_outputs(b, resources);
2426
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002427 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002428}
2429
2430static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002431udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002432{
David Herrmannd7488c22012-03-11 20:05:21 +01002433 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002434 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002435
2436 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002437 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002438 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002439
David Herrmann6ac52db2012-03-11 20:05:22 +01002440 val = udev_device_get_property_value(device, "HOTPLUG");
2441 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002442 return 0;
2443
David Herrmann6ac52db2012-03-11 20:05:22 +01002444 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002445}
2446
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002447static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002448udev_drm_event(int fd, uint32_t mask, void *data)
2449{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002450 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002451 struct udev_device *event;
2452
Giulio Camuffo954f1832014-10-11 18:27:30 +03002453 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002454
Giulio Camuffo954f1832014-10-11 18:27:30 +03002455 if (udev_event_is_hotplug(b, event))
Pekka Paalanend2e62422017-09-08 15:48:07 +03002456 drm_backend_update_heads(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002457
2458 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002459
2460 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002461}
2462
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002463static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002464drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002465{
Armin Krezović545dba62016-08-05 15:54:18 +02002466 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002467 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002468
Giulio Camuffo954f1832014-10-11 18:27:30 +03002469 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002470
Giulio Camuffo954f1832014-10-11 18:27:30 +03002471 wl_event_source_remove(b->udev_drm_source);
2472 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002473
Daniel Stoneb57c6a02017-10-05 16:27:21 +01002474 b->shutting_down = true;
2475
Giulio Camuffo954f1832014-10-11 18:27:30 +03002476 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002477
Marius Vlad7e4db952019-04-17 13:47:06 +03002478 weston_compositor_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002479 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002480 weston_compositor_shutdown(ec);
2481
Pekka Paalanenc112f002017-08-28 16:27:20 +03002482 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
2483 drm_head_destroy(to_drm_head(base));
2484
Giulio Camuffo954f1832014-10-11 18:27:30 +03002485 if (b->gbm)
2486 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002487
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02002488 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03002489 udev_unref(b->udev);
2490
Giulio Camuffo954f1832014-10-11 18:27:30 +03002491 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002492
Daniel Stone087ddf02017-02-14 17:51:30 +00002493 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00002494
Giulio Camuffo954f1832014-10-11 18:27:30 +03002495 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02002496 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002497 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002498}
2499
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002500static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002501session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002502{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002503 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02002504 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01002505 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002506 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002507
Giulio Camuffo954f1832014-10-11 18:27:30 +03002508 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002509 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00002510 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002511 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00002512 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002513 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002514 } else {
2515 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002516 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002517
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002518 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002519
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002520 /* If we have a repaint scheduled (either from a
2521 * pending pageflip or the idle handler), make sure we
2522 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002523 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002524 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002525 * back, we schedule a repaint, which will process
2526 * pending frame callbacks. */
2527
Giulio Camuffo954f1832014-10-11 18:27:30 +03002528 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00002529 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002530 if (output->cursor_plane)
2531 drmModeSetCursor(b->drm.fd, output->crtc_id,
2532 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002533 }
2534
Giulio Camuffo954f1832014-10-11 18:27:30 +03002535 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002536 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002537
Daniel Stone085d2b92015-05-21 00:00:57 +01002538 wl_list_for_each(plane, &b->plane_list, link) {
2539 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
2540 continue;
2541
Giulio Camuffo954f1832014-10-11 18:27:30 +03002542 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01002543 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002544 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002545 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01002546 }
2547 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002548}
2549
Robert Beckett8d23ab72019-06-13 16:55:44 +01002550
2551/**
2552 * Handle KMS GPU being added/removed
2553 *
2554 * If the device being added/removed is the KMS device, we activate/deactivate
2555 * the compositor session.
2556 *
2557 * @param compositor The compositor instance.
2558 * @param device The device being added/removed.
2559 * @param added Whether the device is being added (or removed)
2560 */
2561static void
2562drm_device_changed(struct weston_compositor *compositor,
2563 dev_t device, bool added)
2564{
2565 struct drm_backend *b = to_drm_backend(compositor);
2566
Robert Beckett49dc3202019-07-02 16:31:22 +01002567 if (b->drm.fd < 0 || b->drm.devnum != device ||
2568 compositor->session_active == added)
Robert Beckett8d23ab72019-06-13 16:55:44 +01002569 return;
2570
2571 compositor->session_active = added;
2572 wl_signal_emit(&compositor->session_signal, compositor);
2573}
2574
Daniel Stoneefa504f2016-12-19 16:48:20 +00002575/**
2576 * Determines whether or not a device is capable of modesetting. If successful,
2577 * sets b->drm.fd and b->drm.filename to the opened device.
2578 */
2579static bool
2580drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2581{
2582 const char *filename = udev_device_get_devnode(device);
2583 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002584 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002585 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02002586 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002587
2588 if (!filename)
2589 return false;
2590
2591 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
2592 if (fd < 0)
2593 return false;
2594
2595 res = drmModeGetResources(fd);
2596 if (!res)
2597 goto out_fd;
2598
2599 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2600 res->count_encoders <= 0)
2601 goto out_res;
2602
2603 if (sysnum)
2604 id = atoi(sysnum);
2605 if (!sysnum || id < 0) {
2606 weston_log("couldn't get sysnum for device %s\n", filename);
2607 goto out_res;
2608 }
2609
2610 /* We can be called successfully on multiple devices; if we have,
2611 * clean up old entries. */
2612 if (b->drm.fd >= 0)
2613 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2614 free(b->drm.filename);
2615
2616 b->drm.fd = fd;
2617 b->drm.id = id;
2618 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002619 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002620
Sergi Granellceb59812017-03-28 12:44:04 +02002621 drmModeFreeResources(res);
2622
Daniel Stoneefa504f2016-12-19 16:48:20 +00002623 return true;
2624
2625out_res:
2626 drmModeFreeResources(res);
2627out_fd:
2628 weston_launcher_close(b->compositor->launcher, fd);
2629 return false;
2630}
2631
David Herrmann0af066f2012-10-29 19:21:16 +01002632/*
2633 * Find primary GPU
2634 * Some systems may have multiple DRM devices attached to a single seat. This
2635 * function loops over all devices and tries to find a PCI device with the
2636 * boot_vga sysfs attribute set to 1.
2637 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00002638 * Devices are also vetted to make sure they are are capable of modesetting,
2639 * rather than pure render nodes (GPU with no display), or pure
2640 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01002641 */
2642static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002643find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002644{
2645 struct udev_enumerate *e;
2646 struct udev_list_entry *entry;
2647 const char *path, *device_seat, *id;
2648 struct udev_device *device, *drm_device, *pci;
2649
Giulio Camuffo954f1832014-10-11 18:27:30 +03002650 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002651 udev_enumerate_add_match_subsystem(e, "drm");
2652 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2653
2654 udev_enumerate_scan_devices(e);
2655 drm_device = NULL;
2656 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00002657 bool is_boot_vga = false;
2658
David Herrmann0af066f2012-10-29 19:21:16 +01002659 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002660 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002661 if (!device)
2662 continue;
2663 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2664 if (!device_seat)
2665 device_seat = default_seat;
2666 if (strcmp(device_seat, seat)) {
2667 udev_device_unref(device);
2668 continue;
2669 }
2670
2671 pci = udev_device_get_parent_with_subsystem_devtype(device,
2672 "pci", NULL);
2673 if (pci) {
2674 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00002675 if (id && !strcmp(id, "1"))
2676 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01002677 }
2678
Daniel Stoneefa504f2016-12-19 16:48:20 +00002679 /* If we already have a modesetting-capable device, and this
2680 * device isn't our boot-VGA device, we aren't going to use
2681 * it. */
2682 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01002683 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002684 continue;
2685 }
2686
2687 /* Make sure this device is actually capable of modesetting;
2688 * if this call succeeds, b->drm.{fd,filename} will be set,
2689 * and any old values freed. */
2690 if (!drm_device_is_kms(b, device)) {
2691 udev_device_unref(device);
2692 continue;
2693 }
2694
2695 /* There can only be one boot_vga device, and we try to use it
2696 * at all costs. */
2697 if (is_boot_vga) {
2698 if (drm_device)
2699 udev_device_unref(drm_device);
2700 drm_device = device;
2701 break;
2702 }
2703
2704 /* Per the (!is_boot_vga && drm_device) test above, we only
2705 * trump existing saved devices with boot-VGA devices, so if
2706 * we end up here, this must be the first device we've seen. */
2707 assert(!drm_device);
2708 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01002709 }
2710
Daniel Stoneefa504f2016-12-19 16:48:20 +00002711 /* If we're returning a device to use, we must have an open FD for
2712 * it. */
2713 assert(!!drm_device == (b->drm.fd >= 0));
2714
David Herrmann0af066f2012-10-29 19:21:16 +01002715 udev_enumerate_unref(e);
2716 return drm_device;
2717}
2718
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002719static struct udev_device *
2720open_specific_drm_device(struct drm_backend *b, const char *name)
2721{
2722 struct udev_device *device;
2723
2724 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2725 if (!device) {
2726 weston_log("ERROR: could not open DRM device '%s'\n", name);
2727 return NULL;
2728 }
2729
2730 if (!drm_device_is_kms(b, device)) {
2731 udev_device_unref(device);
2732 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2733 return NULL;
2734 }
2735
2736 /* If we're returning a device to use, we must have an open FD for
2737 * it. */
2738 assert(b->drm.fd >= 0);
2739
2740 return device;
2741}
2742
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002743static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002744planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2745 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002746{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002747 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002748
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002749 switch (key) {
2750 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002751 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002752 break;
2753 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01002754 /* We don't support overlay-plane usage with legacy KMS. */
2755 if (b->atomic_modeset)
2756 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002757 break;
2758 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002759 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002760 break;
2761 default:
2762 break;
2763 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002764}
2765
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002766#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002767static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002768recorder_destroy(struct drm_output *output)
2769{
2770 vaapi_recorder_destroy(output->recorder);
2771 output->recorder = NULL;
2772
2773 output->base.disable_planes--;
2774
2775 wl_list_remove(&output->recorder_frame_listener.link);
2776 weston_log("[libva recorder] done\n");
2777}
2778
2779static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002780recorder_frame_notify(struct wl_listener *listener, void *data)
2781{
2782 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002783 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002784 int fd, ret;
2785
2786 output = container_of(listener, struct drm_output,
2787 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02002788 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002789
2790 if (!output->recorder)
2791 return;
2792
Daniel Stonee2e80132018-01-16 15:37:33 +00002793 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002794 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002795 DRM_CLOEXEC, &fd);
2796 if (ret) {
2797 weston_log("[libva recorder] "
2798 "failed to create prime fd for front buffer\n");
2799 return;
2800 }
2801
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002802 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002803 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002804 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002805 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002806 recorder_destroy(output);
2807 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002808}
2809
2810static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002811create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002812 const char *filename)
2813{
2814 int fd;
2815 drm_magic_t magic;
2816
Giulio Camuffo954f1832014-10-11 18:27:30 +03002817 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002818 if (fd < 0)
2819 return NULL;
2820
2821 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002822 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002823
2824 return vaapi_recorder_create(fd, width, height, filename);
2825}
2826
2827static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002828recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2829 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002830{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002831 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002832 struct drm_output *output;
2833 int width, height;
2834
Giulio Camuffo954f1832014-10-11 18:27:30 +03002835 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002836 struct drm_output, base.link);
2837
2838 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01002839 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002840 weston_log("failed to start vaapi recorder: "
2841 "output format not supported\n");
2842 return;
2843 }
2844
Hardeningff39efa2013-09-18 23:56:35 +02002845 width = output->base.current_mode->width;
2846 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002847
2848 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002849 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002850 if (!output->recorder) {
2851 weston_log("failed to create vaapi recorder\n");
2852 return;
2853 }
2854
2855 output->base.disable_planes++;
2856
2857 output->recorder_frame_listener.notify = recorder_frame_notify;
2858 wl_signal_add(&output->base.frame_signal,
2859 &output->recorder_frame_listener);
2860
2861 weston_output_schedule_repaint(&output->base);
2862
2863 weston_log("[libva recorder] initialized\n");
2864 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002865 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002866 }
2867}
2868#else
2869static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002870recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2871 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002872{
2873 weston_log("Compiled without libva support\n");
2874}
2875#endif
2876
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002877static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002878switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002879{
2880 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002881 bool dmabuf_support_inited;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002882 bool linux_explicit_sync_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002883
Giulio Camuffo954f1832014-10-11 18:27:30 +03002884 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002885 return;
2886
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002887 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002888 linux_explicit_sync_inited =
2889 b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002890
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002891 weston_log("Switching to GL renderer\n");
2892
Giulio Camuffo954f1832014-10-11 18:27:30 +03002893 b->gbm = create_gbm_device(b->drm.fd);
2894 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002895 weston_log("Failed to create gbm device. "
2896 "Aborting renderer switch\n");
2897 return;
2898 }
2899
Giulio Camuffo954f1832014-10-11 18:27:30 +03002900 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002901 pixman_renderer_output_destroy(&output->base);
2902
Giulio Camuffo954f1832014-10-11 18:27:30 +03002903 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002904
Giulio Camuffo954f1832014-10-11 18:27:30 +03002905 if (drm_backend_create_gl_renderer(b) < 0) {
2906 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002907 weston_log("Failed to create GL renderer. Quitting.\n");
2908 /* FIXME: we need a function to shutdown cleanly */
2909 assert(0);
2910 }
2911
Giulio Camuffo954f1832014-10-11 18:27:30 +03002912 wl_list_for_each(output, &b->compositor->output_list, base.link)
2913 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002914
Giulio Camuffo954f1832014-10-11 18:27:30 +03002915 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002916
2917 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
2918 if (linux_dmabuf_setup(b->compositor) < 0)
2919 weston_log("Error: initializing dmabuf "
2920 "support failed.\n");
2921 }
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002922
2923 if (!linux_explicit_sync_inited &&
2924 (b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC)) {
2925 if (linux_explicit_synchronization_setup(b->compositor) < 0)
2926 weston_log("Error: initializing explicit "
2927 " synchronization support failed.\n");
2928 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002929}
2930
2931static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002932renderer_switch_binding(struct weston_keyboard *keyboard,
2933 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002934{
Derek Foreman8ae2db52015-07-15 13:00:36 -05002935 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02002936 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002937
Giulio Camuffo954f1832014-10-11 18:27:30 +03002938 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002939}
2940
Antonio Borneoc90fccc2019-06-30 15:51:10 +02002941static int
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002942drm_virtual_output_start_repaint_loop(struct weston_output *output_base)
2943{
2944 weston_output_finish_frame(output_base, NULL,
2945 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +02002946
2947 return 0;
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002948}
2949
2950static int
2951drm_virtual_output_submit_frame(struct drm_output *output,
2952 struct drm_fb *fb)
2953{
2954 struct drm_backend *b = to_drm_backend(output->base.compositor);
2955 int fd, ret;
2956
2957 assert(fb->num_planes == 1);
2958 ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd);
2959 if (ret) {
2960 weston_log("drmPrimeHandleFD failed, errno=%d\n", errno);
2961 return -1;
2962 }
2963
2964 drm_fb_ref(fb);
2965 ret = output->virtual_submit_frame(&output->base, fd, fb->strides[0],
2966 fb);
2967 if (ret < 0) {
2968 drm_fb_unref(fb);
2969 close(fd);
2970 }
2971 return ret;
2972}
2973
2974static int
2975drm_virtual_output_repaint(struct weston_output *output_base,
2976 pixman_region32_t *damage,
2977 void *repaint_data)
2978{
2979 struct drm_pending_state *pending_state = repaint_data;
2980 struct drm_output_state *state = NULL;
2981 struct drm_output *output = to_drm_output(output_base);
2982 struct drm_plane *scanout_plane = output->scanout_plane;
2983 struct drm_plane_state *scanout_state;
2984
2985 assert(output->virtual);
2986
2987 if (output->disable_pending || output->destroy_pending)
2988 goto err;
2989
2990 /* Drop frame if there isn't free buffers */
2991 if (!gbm_surface_has_free_buffers(output->gbm_surface)) {
2992 weston_log("%s: Drop frame!!\n", __func__);
2993 return -1;
2994 }
2995
2996 assert(!output->state_last);
2997
2998 /* If planes have been disabled in the core, we might not have
2999 * hit assign_planes at all, so might not have valid output state
3000 * here. */
3001 state = drm_pending_state_get_output(pending_state, output);
3002 if (!state)
3003 state = drm_output_state_duplicate(output->state_cur,
3004 pending_state,
3005 DRM_OUTPUT_STATE_CLEAR_PLANES);
3006
3007 drm_output_render(state, damage);
3008 scanout_state = drm_output_state_get_plane(state, scanout_plane);
3009 if (!scanout_state || !scanout_state->fb)
3010 goto err;
3011
3012 if (drm_virtual_output_submit_frame(output, scanout_state->fb) < 0)
3013 goto err;
3014
3015 return 0;
3016
3017err:
3018 drm_output_state_free(state);
3019 return -1;
3020}
3021
3022static void
3023drm_virtual_output_deinit(struct weston_output *base)
3024{
3025 struct drm_output *output = to_drm_output(base);
3026
3027 drm_output_fini_egl(output);
3028
3029 drm_virtual_plane_destroy(output->scanout_plane);
3030}
3031
3032static void
3033drm_virtual_output_destroy(struct weston_output *base)
3034{
3035 struct drm_output *output = to_drm_output(base);
3036
3037 assert(output->virtual);
3038
3039 if (output->base.enabled)
3040 drm_virtual_output_deinit(&output->base);
3041
3042 weston_output_release(&output->base);
3043
3044 drm_output_state_free(output->state_cur);
3045
3046 free(output);
3047}
3048
3049static int
3050drm_virtual_output_enable(struct weston_output *output_base)
3051{
3052 struct drm_output *output = to_drm_output(output_base);
3053 struct drm_backend *b = to_drm_backend(output_base->compositor);
3054
3055 assert(output->virtual);
3056
3057 if (b->use_pixman) {
3058 weston_log("Not support pixman renderer on Virtual output\n");
3059 goto err;
3060 }
3061
3062 if (!output->virtual_submit_frame) {
3063 weston_log("The virtual_submit_frame hook is not set\n");
3064 goto err;
3065 }
3066
3067 output->scanout_plane = drm_virtual_plane_create(b, output);
3068 if (!output->scanout_plane) {
3069 weston_log("Failed to find primary plane for output %s\n",
3070 output->base.name);
3071 return -1;
3072 }
3073
3074 if (drm_output_init_egl(output, b) < 0) {
3075 weston_log("Failed to init output gl state\n");
3076 goto err;
3077 }
3078
3079 output->base.start_repaint_loop = drm_virtual_output_start_repaint_loop;
3080 output->base.repaint = drm_virtual_output_repaint;
3081 output->base.assign_planes = drm_assign_planes;
3082 output->base.set_dpms = NULL;
3083 output->base.switch_mode = NULL;
3084 output->base.gamma_size = 0;
3085 output->base.set_gamma = NULL;
3086
3087 weston_compositor_stack_plane(b->compositor,
3088 &output->scanout_plane->base,
3089 &b->compositor->primary_plane);
3090
3091 return 0;
3092err:
3093 return -1;
3094}
3095
3096static int
3097drm_virtual_output_disable(struct weston_output *base)
3098{
3099 struct drm_output *output = to_drm_output(base);
3100
3101 assert(output->virtual);
3102
3103 if (output->base.enabled)
3104 drm_virtual_output_deinit(&output->base);
3105
3106 return 0;
3107}
3108
3109static struct weston_output *
3110drm_virtual_output_create(struct weston_compositor *c, char *name)
3111{
3112 struct drm_output *output;
3113
3114 output = zalloc(sizeof *output);
3115 if (!output)
3116 return NULL;
3117
3118 output->virtual = true;
3119 output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
3120
3121 weston_output_init(&output->base, c, name);
3122
3123 output->base.enable = drm_virtual_output_enable;
3124 output->base.destroy = drm_virtual_output_destroy;
3125 output->base.disable = drm_virtual_output_disable;
3126 output->base.attach_head = NULL;
3127
3128 output->state_cur = drm_output_state_alloc(output, NULL);
3129
3130 weston_compositor_add_pending_output(&output->base, c);
3131
3132 return &output->base;
3133}
3134
3135static uint32_t
3136drm_virtual_output_set_gbm_format(struct weston_output *base,
3137 const char *gbm_format)
3138{
3139 struct drm_output *output = to_drm_output(base);
3140 struct drm_backend *b = to_drm_backend(base->compositor);
3141
3142 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
3143 output->gbm_format = b->gbm_format;
3144
3145 return output->gbm_format;
3146}
3147
3148static void
3149drm_virtual_output_set_submit_frame_cb(struct weston_output *output_base,
3150 submit_frame_cb cb)
3151{
3152 struct drm_output *output = to_drm_output(output_base);
3153
3154 output->virtual_submit_frame = cb;
3155}
3156
3157static int
3158drm_virtual_output_get_fence_fd(struct weston_output *output_base)
3159{
3160 return gl_renderer->create_fence_fd(output_base);
3161}
3162
3163static void
3164drm_virtual_output_buffer_released(struct drm_fb *fb)
3165{
3166 drm_fb_unref(fb);
3167}
3168
3169static void
3170drm_virtual_output_finish_frame(struct weston_output *output_base,
3171 struct timespec *stamp,
3172 uint32_t presented_flags)
3173{
3174 struct drm_output *output = to_drm_output(output_base);
3175 struct drm_plane_state *ps;
3176
3177 wl_list_for_each(ps, &output->state_cur->plane_list, link)
3178 ps->complete = true;
3179
3180 drm_output_state_free(output->state_last);
3181 output->state_last = NULL;
3182
3183 weston_output_finish_frame(&output->base, stamp, presented_flags);
3184
3185 /* We can't call this from frame_notify, because the output's
3186 * repaint needed flag is cleared just after that */
3187 if (output->recorder)
3188 weston_output_schedule_repaint(&output->base);
3189}
3190
Armin Krezović08368132016-09-30 14:11:05 +02003191static const struct weston_drm_output_api api = {
3192 drm_output_set_mode,
3193 drm_output_set_gbm_format,
3194 drm_output_set_seat,
3195};
3196
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003197static const struct weston_drm_virtual_output_api virt_api = {
3198 drm_virtual_output_create,
3199 drm_virtual_output_set_gbm_format,
3200 drm_virtual_output_set_submit_frame_cb,
3201 drm_virtual_output_get_fence_fd,
3202 drm_virtual_output_buffer_released,
3203 drm_virtual_output_finish_frame
3204};
3205
Giulio Camuffo954f1832014-10-11 18:27:30 +03003206static struct drm_backend *
3207drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003208 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003209{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003210 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01003211 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003212 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003213 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04003214 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02003215 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003216
nerdopolisb16c4ac2018-06-29 08:17:46 -04003217 session_seat = getenv("XDG_SEAT");
3218 if (session_seat)
3219 seat_id = session_seat;
3220
3221 if (config->seat_id)
3222 seat_id = config->seat_id;
3223
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003224 weston_log("initializing drm backend\n");
3225
Giulio Camuffo954f1832014-10-11 18:27:30 +03003226 b = zalloc(sizeof *b);
3227 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003228 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003229
Daniel Stone6020f472018-02-05 15:46:20 +00003230 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003231 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00003232 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00003233
Giulio Camuffo954f1832014-10-11 18:27:30 +03003234 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003235 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00003236 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02003237 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003238
Marius Vlad7e4db952019-04-17 13:47:06 +03003239 b->debug = weston_compositor_add_log_scope(compositor->weston_log_ctx,
3240 "drm-backend",
3241 "Debug messages from DRM/KMS backend\n",
3242 NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003243
Pekka Paalanen7da9a382017-08-30 11:29:49 +03003244 compositor->backend = &b->base;
3245
Stefan Agner0bfebeb2019-07-08 00:30:44 +02003246 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003247 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003248
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003249 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003250 compositor->launcher = weston_launcher_connect(compositor, config->tty,
3251 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003252 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02003253 weston_log("fatal: drm backend should be run using "
3254 "weston-launch binary, or your system should "
3255 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003256 goto err_compositor;
3257 }
3258
Giulio Camuffo954f1832014-10-11 18:27:30 +03003259 b->udev = udev_new();
3260 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003261 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003262 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003263 }
3264
Giulio Camuffo954f1832014-10-11 18:27:30 +03003265 b->session_listener.notify = session_notify;
3266 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003267
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03003268 if (config->specific_device)
3269 drm_device = open_specific_drm_device(b, config->specific_device);
3270 else
3271 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003272 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003273 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003274 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003275 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003276
Daniel Stoneefa504f2016-12-19 16:48:20 +00003277 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003278 weston_log("failed to initialize kms\n");
3279 goto err_udev_dev;
3280 }
3281
Giulio Camuffo954f1832014-10-11 18:27:30 +03003282 if (b->use_pixman) {
3283 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003284 weston_log("failed to initialize pixman renderer\n");
3285 goto err_udev_dev;
3286 }
3287 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003288 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003289 weston_log("failed to initialize egl\n");
3290 goto err_udev_dev;
3291 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003292 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003293
Giulio Camuffo954f1832014-10-11 18:27:30 +03003294 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003295 b->base.repaint_begin = drm_repaint_begin;
3296 b->base.repaint_flush = drm_repaint_flush;
3297 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03003298 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01003299 b->base.device_changed = drm_device_changed;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003300
Bob Ham91880f12016-01-12 10:21:47 +00003301 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003302
Daniel Stone085d2b92015-05-21 00:00:57 +01003303 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003304 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003305
Giulio Camuffo954f1832014-10-11 18:27:30 +03003306 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03003307 compositor, b->udev, seat_id,
3308 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003309 weston_log("failed to create input devices\n");
3310 goto err_sprite;
3311 }
3312
Pekka Paalanend2e62422017-09-08 15:48:07 +03003313 if (drm_backend_create_heads(b, drm_device) < 0) {
3314 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003315 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003316 }
3317
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003318 /* A this point we have some idea of whether or not we have a working
3319 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003320 if (!b->cursors_are_broken)
3321 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003322
Giulio Camuffo954f1832014-10-11 18:27:30 +03003323 loop = wl_display_get_event_loop(compositor->wl_display);
3324 b->drm_source =
3325 wl_event_loop_add_fd(loop, b->drm.fd,
3326 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003327
Giulio Camuffo954f1832014-10-11 18:27:30 +03003328 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3329 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05003330 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003331 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003332 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003333 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003334 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003335 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003336 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003337 udev_monitor_get_fd(b->udev_monitor),
3338 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003339
Giulio Camuffo954f1832014-10-11 18:27:30 +03003340 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003341 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003342 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003343 }
3344
Daniel Stonea96b93c2012-06-22 14:04:37 +01003345 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003346
Giulio Camuffo954f1832014-10-11 18:27:30 +03003347 weston_compositor_add_debug_binding(compositor, KEY_O,
3348 planes_binding, b);
3349 weston_compositor_add_debug_binding(compositor, KEY_C,
3350 planes_binding, b);
3351 weston_compositor_add_debug_binding(compositor, KEY_V,
3352 planes_binding, b);
3353 weston_compositor_add_debug_binding(compositor, KEY_Q,
3354 recorder_binding, b);
3355 weston_compositor_add_debug_binding(compositor, KEY_W,
3356 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003357
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003358 if (compositor->renderer->import_dmabuf) {
3359 if (linux_dmabuf_setup(compositor) < 0)
3360 weston_log("Error: initializing dmabuf "
3361 "support failed.\n");
3362 }
3363
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003364 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
3365 if (linux_explicit_synchronization_setup(compositor) < 0)
3366 weston_log("Error: initializing explicit "
3367 " synchronization support failed.\n");
3368 }
3369
Armin Krezović08368132016-09-30 14:11:05 +02003370 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
3371 &api, sizeof(api));
3372
3373 if (ret < 0) {
3374 weston_log("Failed to register output API.\n");
3375 goto err_udev_monitor;
3376 }
3377
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003378 ret = weston_plugin_api_register(compositor,
3379 WESTON_DRM_VIRTUAL_OUTPUT_API_NAME,
3380 &virt_api, sizeof(virt_api));
3381 if (ret < 0) {
3382 weston_log("Failed to register virtual output API.\n");
3383 goto err_udev_monitor;
3384 }
3385
Giulio Camuffo954f1832014-10-11 18:27:30 +03003386 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003387
3388err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003389 wl_event_source_remove(b->udev_drm_source);
3390 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003391err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003392 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003393err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003394 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003395err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01003396 if (b->gbm)
3397 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003398 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003399err_udev_dev:
3400 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003401err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003402 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003403err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003404 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003405err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003406 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003407 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003408 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003409}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003410
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003411static void
3412config_init_to_defaults(struct weston_drm_backend_config *config)
3413{
Pekka Paalanendee412d2018-04-23 11:44:58 +02003414 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003415}
3416
Giulio Camuffo954f1832014-10-11 18:27:30 +03003417WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01003418weston_backend_init(struct weston_compositor *compositor,
3419 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003420{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003421 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003422 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003423
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003424 if (config_base == NULL ||
3425 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3426 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3427 weston_log("drm backend config structure is invalid\n");
3428 return -1;
3429 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02003430
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003431 config_init_to_defaults(&config);
3432 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003433
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003434 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003435 if (b == NULL)
3436 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003437
Giulio Camuffo954f1832014-10-11 18:27:30 +03003438 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003439}