blob: d513010cda36ac2ab9421c790a2cfd29a2867b87 [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
2567 if (b->drm.fd < 0 || b->drm.devnum != device)
2568 return;
2569
2570 compositor->session_active = added;
2571 wl_signal_emit(&compositor->session_signal, compositor);
2572}
2573
Daniel Stoneefa504f2016-12-19 16:48:20 +00002574/**
2575 * Determines whether or not a device is capable of modesetting. If successful,
2576 * sets b->drm.fd and b->drm.filename to the opened device.
2577 */
2578static bool
2579drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2580{
2581 const char *filename = udev_device_get_devnode(device);
2582 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002583 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002584 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02002585 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002586
2587 if (!filename)
2588 return false;
2589
2590 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
2591 if (fd < 0)
2592 return false;
2593
2594 res = drmModeGetResources(fd);
2595 if (!res)
2596 goto out_fd;
2597
2598 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2599 res->count_encoders <= 0)
2600 goto out_res;
2601
2602 if (sysnum)
2603 id = atoi(sysnum);
2604 if (!sysnum || id < 0) {
2605 weston_log("couldn't get sysnum for device %s\n", filename);
2606 goto out_res;
2607 }
2608
2609 /* We can be called successfully on multiple devices; if we have,
2610 * clean up old entries. */
2611 if (b->drm.fd >= 0)
2612 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2613 free(b->drm.filename);
2614
2615 b->drm.fd = fd;
2616 b->drm.id = id;
2617 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002618 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002619
Sergi Granellceb59812017-03-28 12:44:04 +02002620 drmModeFreeResources(res);
2621
Daniel Stoneefa504f2016-12-19 16:48:20 +00002622 return true;
2623
2624out_res:
2625 drmModeFreeResources(res);
2626out_fd:
2627 weston_launcher_close(b->compositor->launcher, fd);
2628 return false;
2629}
2630
David Herrmann0af066f2012-10-29 19:21:16 +01002631/*
2632 * Find primary GPU
2633 * Some systems may have multiple DRM devices attached to a single seat. This
2634 * function loops over all devices and tries to find a PCI device with the
2635 * boot_vga sysfs attribute set to 1.
2636 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00002637 * Devices are also vetted to make sure they are are capable of modesetting,
2638 * rather than pure render nodes (GPU with no display), or pure
2639 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01002640 */
2641static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002642find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002643{
2644 struct udev_enumerate *e;
2645 struct udev_list_entry *entry;
2646 const char *path, *device_seat, *id;
2647 struct udev_device *device, *drm_device, *pci;
2648
Giulio Camuffo954f1832014-10-11 18:27:30 +03002649 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002650 udev_enumerate_add_match_subsystem(e, "drm");
2651 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2652
2653 udev_enumerate_scan_devices(e);
2654 drm_device = NULL;
2655 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00002656 bool is_boot_vga = false;
2657
David Herrmann0af066f2012-10-29 19:21:16 +01002658 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002659 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002660 if (!device)
2661 continue;
2662 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2663 if (!device_seat)
2664 device_seat = default_seat;
2665 if (strcmp(device_seat, seat)) {
2666 udev_device_unref(device);
2667 continue;
2668 }
2669
2670 pci = udev_device_get_parent_with_subsystem_devtype(device,
2671 "pci", NULL);
2672 if (pci) {
2673 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00002674 if (id && !strcmp(id, "1"))
2675 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01002676 }
2677
Daniel Stoneefa504f2016-12-19 16:48:20 +00002678 /* If we already have a modesetting-capable device, and this
2679 * device isn't our boot-VGA device, we aren't going to use
2680 * it. */
2681 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01002682 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002683 continue;
2684 }
2685
2686 /* Make sure this device is actually capable of modesetting;
2687 * if this call succeeds, b->drm.{fd,filename} will be set,
2688 * and any old values freed. */
2689 if (!drm_device_is_kms(b, device)) {
2690 udev_device_unref(device);
2691 continue;
2692 }
2693
2694 /* There can only be one boot_vga device, and we try to use it
2695 * at all costs. */
2696 if (is_boot_vga) {
2697 if (drm_device)
2698 udev_device_unref(drm_device);
2699 drm_device = device;
2700 break;
2701 }
2702
2703 /* Per the (!is_boot_vga && drm_device) test above, we only
2704 * trump existing saved devices with boot-VGA devices, so if
2705 * we end up here, this must be the first device we've seen. */
2706 assert(!drm_device);
2707 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01002708 }
2709
Daniel Stoneefa504f2016-12-19 16:48:20 +00002710 /* If we're returning a device to use, we must have an open FD for
2711 * it. */
2712 assert(!!drm_device == (b->drm.fd >= 0));
2713
David Herrmann0af066f2012-10-29 19:21:16 +01002714 udev_enumerate_unref(e);
2715 return drm_device;
2716}
2717
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002718static struct udev_device *
2719open_specific_drm_device(struct drm_backend *b, const char *name)
2720{
2721 struct udev_device *device;
2722
2723 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2724 if (!device) {
2725 weston_log("ERROR: could not open DRM device '%s'\n", name);
2726 return NULL;
2727 }
2728
2729 if (!drm_device_is_kms(b, device)) {
2730 udev_device_unref(device);
2731 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2732 return NULL;
2733 }
2734
2735 /* If we're returning a device to use, we must have an open FD for
2736 * it. */
2737 assert(b->drm.fd >= 0);
2738
2739 return device;
2740}
2741
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002742static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002743planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2744 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002745{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002746 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002747
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002748 switch (key) {
2749 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002750 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002751 break;
2752 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01002753 /* We don't support overlay-plane usage with legacy KMS. */
2754 if (b->atomic_modeset)
2755 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002756 break;
2757 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002758 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002759 break;
2760 default:
2761 break;
2762 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002763}
2764
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002765#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002766static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002767recorder_destroy(struct drm_output *output)
2768{
2769 vaapi_recorder_destroy(output->recorder);
2770 output->recorder = NULL;
2771
2772 output->base.disable_planes--;
2773
2774 wl_list_remove(&output->recorder_frame_listener.link);
2775 weston_log("[libva recorder] done\n");
2776}
2777
2778static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002779recorder_frame_notify(struct wl_listener *listener, void *data)
2780{
2781 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002782 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002783 int fd, ret;
2784
2785 output = container_of(listener, struct drm_output,
2786 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02002787 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002788
2789 if (!output->recorder)
2790 return;
2791
Daniel Stonee2e80132018-01-16 15:37:33 +00002792 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002793 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002794 DRM_CLOEXEC, &fd);
2795 if (ret) {
2796 weston_log("[libva recorder] "
2797 "failed to create prime fd for front buffer\n");
2798 return;
2799 }
2800
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002801 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002802 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002803 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002804 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002805 recorder_destroy(output);
2806 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002807}
2808
2809static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002810create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002811 const char *filename)
2812{
2813 int fd;
2814 drm_magic_t magic;
2815
Giulio Camuffo954f1832014-10-11 18:27:30 +03002816 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002817 if (fd < 0)
2818 return NULL;
2819
2820 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002821 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002822
2823 return vaapi_recorder_create(fd, width, height, filename);
2824}
2825
2826static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002827recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2828 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002829{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002830 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002831 struct drm_output *output;
2832 int width, height;
2833
Giulio Camuffo954f1832014-10-11 18:27:30 +03002834 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002835 struct drm_output, base.link);
2836
2837 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01002838 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002839 weston_log("failed to start vaapi recorder: "
2840 "output format not supported\n");
2841 return;
2842 }
2843
Hardeningff39efa2013-09-18 23:56:35 +02002844 width = output->base.current_mode->width;
2845 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002846
2847 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002848 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002849 if (!output->recorder) {
2850 weston_log("failed to create vaapi recorder\n");
2851 return;
2852 }
2853
2854 output->base.disable_planes++;
2855
2856 output->recorder_frame_listener.notify = recorder_frame_notify;
2857 wl_signal_add(&output->base.frame_signal,
2858 &output->recorder_frame_listener);
2859
2860 weston_output_schedule_repaint(&output->base);
2861
2862 weston_log("[libva recorder] initialized\n");
2863 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002864 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002865 }
2866}
2867#else
2868static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002869recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2870 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002871{
2872 weston_log("Compiled without libva support\n");
2873}
2874#endif
2875
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002876static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002877switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002878{
2879 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002880 bool dmabuf_support_inited;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002881 bool linux_explicit_sync_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002882
Giulio Camuffo954f1832014-10-11 18:27:30 +03002883 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002884 return;
2885
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002886 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002887 linux_explicit_sync_inited =
2888 b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002889
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002890 weston_log("Switching to GL renderer\n");
2891
Giulio Camuffo954f1832014-10-11 18:27:30 +03002892 b->gbm = create_gbm_device(b->drm.fd);
2893 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002894 weston_log("Failed to create gbm device. "
2895 "Aborting renderer switch\n");
2896 return;
2897 }
2898
Giulio Camuffo954f1832014-10-11 18:27:30 +03002899 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002900 pixman_renderer_output_destroy(&output->base);
2901
Giulio Camuffo954f1832014-10-11 18:27:30 +03002902 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002903
Giulio Camuffo954f1832014-10-11 18:27:30 +03002904 if (drm_backend_create_gl_renderer(b) < 0) {
2905 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002906 weston_log("Failed to create GL renderer. Quitting.\n");
2907 /* FIXME: we need a function to shutdown cleanly */
2908 assert(0);
2909 }
2910
Giulio Camuffo954f1832014-10-11 18:27:30 +03002911 wl_list_for_each(output, &b->compositor->output_list, base.link)
2912 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002913
Giulio Camuffo954f1832014-10-11 18:27:30 +03002914 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002915
2916 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
2917 if (linux_dmabuf_setup(b->compositor) < 0)
2918 weston_log("Error: initializing dmabuf "
2919 "support failed.\n");
2920 }
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002921
2922 if (!linux_explicit_sync_inited &&
2923 (b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC)) {
2924 if (linux_explicit_synchronization_setup(b->compositor) < 0)
2925 weston_log("Error: initializing explicit "
2926 " synchronization support failed.\n");
2927 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002928}
2929
2930static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002931renderer_switch_binding(struct weston_keyboard *keyboard,
2932 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002933{
Derek Foreman8ae2db52015-07-15 13:00:36 -05002934 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02002935 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002936
Giulio Camuffo954f1832014-10-11 18:27:30 +03002937 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002938}
2939
Antonio Borneoc90fccc2019-06-30 15:51:10 +02002940static int
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002941drm_virtual_output_start_repaint_loop(struct weston_output *output_base)
2942{
2943 weston_output_finish_frame(output_base, NULL,
2944 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +02002945
2946 return 0;
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002947}
2948
2949static int
2950drm_virtual_output_submit_frame(struct drm_output *output,
2951 struct drm_fb *fb)
2952{
2953 struct drm_backend *b = to_drm_backend(output->base.compositor);
2954 int fd, ret;
2955
2956 assert(fb->num_planes == 1);
2957 ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd);
2958 if (ret) {
2959 weston_log("drmPrimeHandleFD failed, errno=%d\n", errno);
2960 return -1;
2961 }
2962
2963 drm_fb_ref(fb);
2964 ret = output->virtual_submit_frame(&output->base, fd, fb->strides[0],
2965 fb);
2966 if (ret < 0) {
2967 drm_fb_unref(fb);
2968 close(fd);
2969 }
2970 return ret;
2971}
2972
2973static int
2974drm_virtual_output_repaint(struct weston_output *output_base,
2975 pixman_region32_t *damage,
2976 void *repaint_data)
2977{
2978 struct drm_pending_state *pending_state = repaint_data;
2979 struct drm_output_state *state = NULL;
2980 struct drm_output *output = to_drm_output(output_base);
2981 struct drm_plane *scanout_plane = output->scanout_plane;
2982 struct drm_plane_state *scanout_state;
2983
2984 assert(output->virtual);
2985
2986 if (output->disable_pending || output->destroy_pending)
2987 goto err;
2988
2989 /* Drop frame if there isn't free buffers */
2990 if (!gbm_surface_has_free_buffers(output->gbm_surface)) {
2991 weston_log("%s: Drop frame!!\n", __func__);
2992 return -1;
2993 }
2994
2995 assert(!output->state_last);
2996
2997 /* If planes have been disabled in the core, we might not have
2998 * hit assign_planes at all, so might not have valid output state
2999 * here. */
3000 state = drm_pending_state_get_output(pending_state, output);
3001 if (!state)
3002 state = drm_output_state_duplicate(output->state_cur,
3003 pending_state,
3004 DRM_OUTPUT_STATE_CLEAR_PLANES);
3005
3006 drm_output_render(state, damage);
3007 scanout_state = drm_output_state_get_plane(state, scanout_plane);
3008 if (!scanout_state || !scanout_state->fb)
3009 goto err;
3010
3011 if (drm_virtual_output_submit_frame(output, scanout_state->fb) < 0)
3012 goto err;
3013
3014 return 0;
3015
3016err:
3017 drm_output_state_free(state);
3018 return -1;
3019}
3020
3021static void
3022drm_virtual_output_deinit(struct weston_output *base)
3023{
3024 struct drm_output *output = to_drm_output(base);
3025
3026 drm_output_fini_egl(output);
3027
3028 drm_virtual_plane_destroy(output->scanout_plane);
3029}
3030
3031static void
3032drm_virtual_output_destroy(struct weston_output *base)
3033{
3034 struct drm_output *output = to_drm_output(base);
3035
3036 assert(output->virtual);
3037
3038 if (output->base.enabled)
3039 drm_virtual_output_deinit(&output->base);
3040
3041 weston_output_release(&output->base);
3042
3043 drm_output_state_free(output->state_cur);
3044
3045 free(output);
3046}
3047
3048static int
3049drm_virtual_output_enable(struct weston_output *output_base)
3050{
3051 struct drm_output *output = to_drm_output(output_base);
3052 struct drm_backend *b = to_drm_backend(output_base->compositor);
3053
3054 assert(output->virtual);
3055
3056 if (b->use_pixman) {
3057 weston_log("Not support pixman renderer on Virtual output\n");
3058 goto err;
3059 }
3060
3061 if (!output->virtual_submit_frame) {
3062 weston_log("The virtual_submit_frame hook is not set\n");
3063 goto err;
3064 }
3065
3066 output->scanout_plane = drm_virtual_plane_create(b, output);
3067 if (!output->scanout_plane) {
3068 weston_log("Failed to find primary plane for output %s\n",
3069 output->base.name);
3070 return -1;
3071 }
3072
3073 if (drm_output_init_egl(output, b) < 0) {
3074 weston_log("Failed to init output gl state\n");
3075 goto err;
3076 }
3077
3078 output->base.start_repaint_loop = drm_virtual_output_start_repaint_loop;
3079 output->base.repaint = drm_virtual_output_repaint;
3080 output->base.assign_planes = drm_assign_planes;
3081 output->base.set_dpms = NULL;
3082 output->base.switch_mode = NULL;
3083 output->base.gamma_size = 0;
3084 output->base.set_gamma = NULL;
3085
3086 weston_compositor_stack_plane(b->compositor,
3087 &output->scanout_plane->base,
3088 &b->compositor->primary_plane);
3089
3090 return 0;
3091err:
3092 return -1;
3093}
3094
3095static int
3096drm_virtual_output_disable(struct weston_output *base)
3097{
3098 struct drm_output *output = to_drm_output(base);
3099
3100 assert(output->virtual);
3101
3102 if (output->base.enabled)
3103 drm_virtual_output_deinit(&output->base);
3104
3105 return 0;
3106}
3107
3108static struct weston_output *
3109drm_virtual_output_create(struct weston_compositor *c, char *name)
3110{
3111 struct drm_output *output;
3112
3113 output = zalloc(sizeof *output);
3114 if (!output)
3115 return NULL;
3116
3117 output->virtual = true;
3118 output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
3119
3120 weston_output_init(&output->base, c, name);
3121
3122 output->base.enable = drm_virtual_output_enable;
3123 output->base.destroy = drm_virtual_output_destroy;
3124 output->base.disable = drm_virtual_output_disable;
3125 output->base.attach_head = NULL;
3126
3127 output->state_cur = drm_output_state_alloc(output, NULL);
3128
3129 weston_compositor_add_pending_output(&output->base, c);
3130
3131 return &output->base;
3132}
3133
3134static uint32_t
3135drm_virtual_output_set_gbm_format(struct weston_output *base,
3136 const char *gbm_format)
3137{
3138 struct drm_output *output = to_drm_output(base);
3139 struct drm_backend *b = to_drm_backend(base->compositor);
3140
3141 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
3142 output->gbm_format = b->gbm_format;
3143
3144 return output->gbm_format;
3145}
3146
3147static void
3148drm_virtual_output_set_submit_frame_cb(struct weston_output *output_base,
3149 submit_frame_cb cb)
3150{
3151 struct drm_output *output = to_drm_output(output_base);
3152
3153 output->virtual_submit_frame = cb;
3154}
3155
3156static int
3157drm_virtual_output_get_fence_fd(struct weston_output *output_base)
3158{
3159 return gl_renderer->create_fence_fd(output_base);
3160}
3161
3162static void
3163drm_virtual_output_buffer_released(struct drm_fb *fb)
3164{
3165 drm_fb_unref(fb);
3166}
3167
3168static void
3169drm_virtual_output_finish_frame(struct weston_output *output_base,
3170 struct timespec *stamp,
3171 uint32_t presented_flags)
3172{
3173 struct drm_output *output = to_drm_output(output_base);
3174 struct drm_plane_state *ps;
3175
3176 wl_list_for_each(ps, &output->state_cur->plane_list, link)
3177 ps->complete = true;
3178
3179 drm_output_state_free(output->state_last);
3180 output->state_last = NULL;
3181
3182 weston_output_finish_frame(&output->base, stamp, presented_flags);
3183
3184 /* We can't call this from frame_notify, because the output's
3185 * repaint needed flag is cleared just after that */
3186 if (output->recorder)
3187 weston_output_schedule_repaint(&output->base);
3188}
3189
Armin Krezović08368132016-09-30 14:11:05 +02003190static const struct weston_drm_output_api api = {
3191 drm_output_set_mode,
3192 drm_output_set_gbm_format,
3193 drm_output_set_seat,
3194};
3195
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003196static const struct weston_drm_virtual_output_api virt_api = {
3197 drm_virtual_output_create,
3198 drm_virtual_output_set_gbm_format,
3199 drm_virtual_output_set_submit_frame_cb,
3200 drm_virtual_output_get_fence_fd,
3201 drm_virtual_output_buffer_released,
3202 drm_virtual_output_finish_frame
3203};
3204
Giulio Camuffo954f1832014-10-11 18:27:30 +03003205static struct drm_backend *
3206drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003207 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003208{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003209 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01003210 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003211 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003212 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04003213 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02003214 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003215
nerdopolisb16c4ac2018-06-29 08:17:46 -04003216 session_seat = getenv("XDG_SEAT");
3217 if (session_seat)
3218 seat_id = session_seat;
3219
3220 if (config->seat_id)
3221 seat_id = config->seat_id;
3222
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003223 weston_log("initializing drm backend\n");
3224
Giulio Camuffo954f1832014-10-11 18:27:30 +03003225 b = zalloc(sizeof *b);
3226 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003227 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003228
Daniel Stone6020f472018-02-05 15:46:20 +00003229 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003230 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00003231 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00003232
Giulio Camuffo954f1832014-10-11 18:27:30 +03003233 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003234 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00003235 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02003236 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003237
Marius Vlad7e4db952019-04-17 13:47:06 +03003238 b->debug = weston_compositor_add_log_scope(compositor->weston_log_ctx,
3239 "drm-backend",
3240 "Debug messages from DRM/KMS backend\n",
3241 NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003242
Pekka Paalanen7da9a382017-08-30 11:29:49 +03003243 compositor->backend = &b->base;
3244
Stefan Agner0bfebeb2019-07-08 00:30:44 +02003245 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003246 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003247
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003248 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003249 compositor->launcher = weston_launcher_connect(compositor, config->tty,
3250 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003251 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02003252 weston_log("fatal: drm backend should be run using "
3253 "weston-launch binary, or your system should "
3254 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003255 goto err_compositor;
3256 }
3257
Giulio Camuffo954f1832014-10-11 18:27:30 +03003258 b->udev = udev_new();
3259 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003260 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003261 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003262 }
3263
Giulio Camuffo954f1832014-10-11 18:27:30 +03003264 b->session_listener.notify = session_notify;
3265 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003266
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03003267 if (config->specific_device)
3268 drm_device = open_specific_drm_device(b, config->specific_device);
3269 else
3270 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003271 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003272 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003273 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003274 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003275
Daniel Stoneefa504f2016-12-19 16:48:20 +00003276 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003277 weston_log("failed to initialize kms\n");
3278 goto err_udev_dev;
3279 }
3280
Giulio Camuffo954f1832014-10-11 18:27:30 +03003281 if (b->use_pixman) {
3282 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003283 weston_log("failed to initialize pixman renderer\n");
3284 goto err_udev_dev;
3285 }
3286 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003287 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003288 weston_log("failed to initialize egl\n");
3289 goto err_udev_dev;
3290 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003291 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003292
Giulio Camuffo954f1832014-10-11 18:27:30 +03003293 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003294 b->base.repaint_begin = drm_repaint_begin;
3295 b->base.repaint_flush = drm_repaint_flush;
3296 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03003297 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01003298 b->base.device_changed = drm_device_changed;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003299
Bob Ham91880f12016-01-12 10:21:47 +00003300 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003301
Daniel Stone085d2b92015-05-21 00:00:57 +01003302 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003303 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003304
Giulio Camuffo954f1832014-10-11 18:27:30 +03003305 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03003306 compositor, b->udev, seat_id,
3307 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003308 weston_log("failed to create input devices\n");
3309 goto err_sprite;
3310 }
3311
Pekka Paalanend2e62422017-09-08 15:48:07 +03003312 if (drm_backend_create_heads(b, drm_device) < 0) {
3313 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003314 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003315 }
3316
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003317 /* A this point we have some idea of whether or not we have a working
3318 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003319 if (!b->cursors_are_broken)
3320 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003321
Giulio Camuffo954f1832014-10-11 18:27:30 +03003322 loop = wl_display_get_event_loop(compositor->wl_display);
3323 b->drm_source =
3324 wl_event_loop_add_fd(loop, b->drm.fd,
3325 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003326
Giulio Camuffo954f1832014-10-11 18:27:30 +03003327 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3328 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05003329 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003330 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003331 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003332 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003333 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003334 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003335 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003336 udev_monitor_get_fd(b->udev_monitor),
3337 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003338
Giulio Camuffo954f1832014-10-11 18:27:30 +03003339 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003340 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003341 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003342 }
3343
Daniel Stonea96b93c2012-06-22 14:04:37 +01003344 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003345
Giulio Camuffo954f1832014-10-11 18:27:30 +03003346 weston_compositor_add_debug_binding(compositor, KEY_O,
3347 planes_binding, b);
3348 weston_compositor_add_debug_binding(compositor, KEY_C,
3349 planes_binding, b);
3350 weston_compositor_add_debug_binding(compositor, KEY_V,
3351 planes_binding, b);
3352 weston_compositor_add_debug_binding(compositor, KEY_Q,
3353 recorder_binding, b);
3354 weston_compositor_add_debug_binding(compositor, KEY_W,
3355 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003356
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003357 if (compositor->renderer->import_dmabuf) {
3358 if (linux_dmabuf_setup(compositor) < 0)
3359 weston_log("Error: initializing dmabuf "
3360 "support failed.\n");
3361 }
3362
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003363 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
3364 if (linux_explicit_synchronization_setup(compositor) < 0)
3365 weston_log("Error: initializing explicit "
3366 " synchronization support failed.\n");
3367 }
3368
Armin Krezović08368132016-09-30 14:11:05 +02003369 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
3370 &api, sizeof(api));
3371
3372 if (ret < 0) {
3373 weston_log("Failed to register output API.\n");
3374 goto err_udev_monitor;
3375 }
3376
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003377 ret = weston_plugin_api_register(compositor,
3378 WESTON_DRM_VIRTUAL_OUTPUT_API_NAME,
3379 &virt_api, sizeof(virt_api));
3380 if (ret < 0) {
3381 weston_log("Failed to register virtual output API.\n");
3382 goto err_udev_monitor;
3383 }
3384
Giulio Camuffo954f1832014-10-11 18:27:30 +03003385 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003386
3387err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003388 wl_event_source_remove(b->udev_drm_source);
3389 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003390err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003391 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003392err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003393 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003394err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01003395 if (b->gbm)
3396 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003397 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003398err_udev_dev:
3399 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003400err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003401 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003402err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003403 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003404err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003405 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003406 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003407 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003408}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003409
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003410static void
3411config_init_to_defaults(struct weston_drm_backend_config *config)
3412{
Pekka Paalanendee412d2018-04-23 11:44:58 +02003413 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003414}
3415
Giulio Camuffo954f1832014-10-11 18:27:30 +03003416WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01003417weston_backend_init(struct weston_compositor *compositor,
3418 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003419{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003420 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003421 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003422
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003423 if (config_base == NULL ||
3424 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3425 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3426 weston_log("drm backend config structure is invalid\n");
3427 return -1;
3428 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02003429
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003430 config_init_to_defaults(&config);
3431 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003432
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003433 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003434 if (b == NULL)
3435 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003436
Giulio Camuffo954f1832014-10-11 18:27:30 +03003437 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003438}