blob: fea5897df36dc0889d4bf394fdae4a3250f06683 [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
Benjamin Franzke060cf802011-04-30 09:32:11 +020050#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040051#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020052
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020053#include <libweston/libweston.h>
Pekka Paalanen75710272019-03-29 16:39:12 +020054#include <libweston/backend-drm.h>
Marius Vladf4f4c2b2019-04-29 13:27:47 +030055#include <libweston/weston-debug.h>
Daniel Stonedd1bc502019-06-17 12:13:46 +010056#include "drm-internal.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070057#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020058#include "shared/timespec-util.h"
Pekka Paalanen81475a52019-04-04 17:29:27 +030059#include "renderer-gl/gl-renderer.h"
Vincent Abriouc9506672016-10-05 16:14:07 +020060#include "weston-egl-ext.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020061#include "pixman-renderer.h"
Daniel Stone0b70fa42017-04-04 17:54:23 +010062#include "pixel-formats.h"
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070063#include "libbacklight.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100064#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010065#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030066#include "vaapi-recorder.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020067#include "presentation-time-server-protocol.h"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030068#include "linux-dmabuf.h"
Micah Fedkec8890122017-02-01 15:28:23 -050069#include "linux-dmabuf-unstable-v1-server-protocol.h"
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030070#include "linux-explicit-synchronization.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040071
Daniel Stone598ee9d2016-11-16 11:55:20 +000072static struct drm_property_enum_info plane_type_enums[] = {
73 [WDRM_PLANE_TYPE_PRIMARY] = {
74 .name = "Primary",
75 },
76 [WDRM_PLANE_TYPE_OVERLAY] = {
77 .name = "Overlay",
78 },
79 [WDRM_PLANE_TYPE_CURSOR] = {
80 .name = "Cursor",
81 },
82};
83
84static const struct drm_property_info plane_props[] = {
85 [WDRM_PLANE_TYPE] = {
86 .name = "type",
87 .enum_values = plane_type_enums,
88 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
89 },
90 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
91 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
92 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
93 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
94 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
95 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
96 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
97 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
98 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
99 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
Sergi Granellf4456222017-01-12 17:17:32 +0000100 [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" },
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300101 [WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
Deepak Rawat009b3cf2018-07-24 14:05:37 -0700102 [WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000103};
104
Daniel Stone76255772018-07-06 11:36:49 +0100105static struct drm_property_enum_info dpms_state_enums[] = {
106 [WDRM_DPMS_STATE_OFF] = {
107 .name = "Off",
108 },
109 [WDRM_DPMS_STATE_ON] = {
110 .name = "On",
111 },
112 [WDRM_DPMS_STATE_STANDBY] = {
113 .name = "Standby",
114 },
115 [WDRM_DPMS_STATE_SUSPEND] = {
116 .name = "Suspend",
117 },
118};
119
Daniel Stone598ee9d2016-11-16 11:55:20 +0000120static const struct drm_property_info connector_props[] = {
121 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
Daniel Stone76255772018-07-06 11:36:49 +0100122 [WDRM_CONNECTOR_DPMS] = {
123 .name = "DPMS",
124 .enum_values = dpms_state_enums,
125 .num_enum_values = WDRM_DPMS_STATE__COUNT,
126 },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000127 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
Philipp Zabel61dc4ca2018-08-30 17:39:51 +0200128 [WDRM_CONNECTOR_NON_DESKTOP] = { .name = "non-desktop", },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000129};
130
Daniel Stone598ee9d2016-11-16 11:55:20 +0000131static const struct drm_property_info crtc_props[] = {
132 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
133 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
134};
135
Pekka Paalanencd011a62016-11-15 22:07:49 +0000136/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000137 * Mode for drm_output_state_duplicate.
138 */
139enum drm_output_state_duplicate_mode {
140 DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
141 DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
142};
143
144/**
145 * Mode for drm_pending_state_apply and co.
146 */
147enum drm_state_apply_mode {
148 DRM_STATE_APPLY_SYNC, /**< state fully processed */
149 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
Daniel Stonebb6c19f2016-12-08 17:27:17 +0000150 DRM_STATE_TEST_ONLY, /**< test if the state can be applied */
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000151};
152
Marius Vlad5d767412018-12-14 11:56:10 +0200153enum drm_output_propose_state_mode {
154 DRM_OUTPUT_PROPOSE_STATE_MIXED, /**< mix renderer & planes */
155 DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY, /**< only assign to renderer & cursor */
156 DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY, /**< no renderer use, only planes */
157};
158
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530159static const char *const aspect_ratio_as_string[] = {
160 [WESTON_MODE_PIC_AR_NONE] = "",
161 [WESTON_MODE_PIC_AR_4_3] = " 4:3",
162 [WESTON_MODE_PIC_AR_16_9] = " 16:9",
163 [WESTON_MODE_PIC_AR_64_27] = " 64:27",
164 [WESTON_MODE_PIC_AR_256_135] = " 256:135",
165};
166
Marius Vlad5d767412018-12-14 11:56:10 +0200167static const char *const drm_output_propose_state_mode_as_string[] = {
168 [DRM_OUTPUT_PROPOSE_STATE_MIXED] = "mixed state",
169 [DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY] = "render-only state",
170 [DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY] = "plane-only state"
171};
172
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300173static struct gl_renderer_interface *gl_renderer;
174
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500175static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400176
Daniel Stone087ddf02017-02-14 17:51:30 +0000177static void
178wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
179{
180 uint32_t *pos, *end;
181
182 end = (uint32_t *) ((char *) array->data + array->size);
183
184 wl_array_for_each(pos, array) {
185 if (*pos != elm)
186 continue;
187
188 array->size -= sizeof(*pos);
189 if (pos + 1 == end)
190 break;
191
192 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
193 break;
194 }
195}
196
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000197static int
198pageflip_timeout(void *data) {
199 /*
200 * Our timer just went off, that means we're not receiving drm
201 * page flip events anymore for that output. Let's gracefully exit
202 * weston with a return value so devs can debug what's going on.
203 */
204 struct drm_output *output = data;
205 struct weston_compositor *compositor = output->base.compositor;
206
207 weston_log("Pageflip timeout reached on output %s, your "
208 "driver is probably buggy! Exiting.\n",
209 output->base.name);
210 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
211
212 return 0;
213}
214
215/* Creates the pageflip timer. Note that it isn't armed by default */
216static int
217drm_output_pageflip_timer_create(struct drm_output *output)
218{
219 struct wl_event_loop *loop = NULL;
220 struct weston_compositor *ec = output->base.compositor;
221
222 loop = wl_display_get_event_loop(ec->wl_display);
223 assert(loop);
224 output->pageflip_timer = wl_event_loop_add_timer(loop,
225 pageflip_timeout,
226 output);
227
228 if (output->pageflip_timer == NULL) {
Antonio Borneo39578632019-04-26 23:57:31 +0200229 weston_log("creating drm pageflip timer failed: %s\n",
230 strerror(errno));
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000231 return -1;
232 }
233
234 return 0;
235}
236
Daniel Stone02cf4662017-03-03 16:19:39 +0000237/**
238 * Get the current value of a KMS property
239 *
240 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
241 * for the target property, return the current value of that property,
242 * with an optional default. If the property is a KMS enum type, the return
243 * value will be translated into the appropriate internal enum.
244 *
245 * If the property is not present, the default value will be returned.
246 *
247 * @param info Internal structure for property to look up
248 * @param props Raw KMS properties for the target object
249 * @param def Value to return if property is not found
250 */
251static uint64_t
252drm_property_get_value(struct drm_property_info *info,
Daniel Stone85eebdf2018-07-05 17:55:43 +0100253 const drmModeObjectProperties *props,
Daniel Stone02cf4662017-03-03 16:19:39 +0000254 uint64_t def)
255{
256 unsigned int i;
257
258 if (info->prop_id == 0)
259 return def;
260
261 for (i = 0; i < props->count_props; i++) {
262 unsigned int j;
263
264 if (props->props[i] != info->prop_id)
265 continue;
266
267 /* Simple (non-enum) types can return the value directly */
268 if (info->num_enum_values == 0)
269 return props->prop_values[i];
270
271 /* Map from raw value to enum value */
272 for (j = 0; j < info->num_enum_values; j++) {
273 if (!info->enum_values[j].valid)
274 continue;
275 if (info->enum_values[j].value != props->prop_values[i])
276 continue;
277
278 return j;
279 }
280
281 /* We don't have a mapping for this enum; return default. */
282 break;
283 }
284
285 return def;
286}
287
288/**
289 * Cache DRM property values
290 *
291 * Update a per-object array of drm_property_info structures, given the
292 * DRM properties of the object.
293 *
294 * Call this every time an object newly appears (note that only connectors
295 * can be hotplugged), the first time it is seen, or when its status changes
296 * in a way which invalidates the potential property values (currently, the
297 * only case for this is connector hotplug).
298 *
299 * This updates the property IDs and enum values within the drm_property_info
300 * array.
301 *
302 * DRM property enum values are dynamic at runtime; the user must query the
303 * property to find out the desired runtime value for a requested string
304 * name. Using the 'type' field on planes as an example, there is no single
305 * hardcoded constant for primary plane types; instead, the property must be
306 * queried at runtime to find the value associated with the string "Primary".
307 *
308 * This helper queries and caches the enum values, to allow us to use a set
309 * of compile-time-constant enums portably across various implementations.
310 * The values given in enum_names are searched for, and stored in the
311 * same-indexed field of the map array.
312 *
313 * @param b DRM backend object
314 * @param src DRM property info array to source from
315 * @param info DRM property info array to copy into
316 * @param num_infos Number of entries in the source array
317 * @param props DRM object properties for the object
318 */
319static void
320drm_property_info_populate(struct drm_backend *b,
321 const struct drm_property_info *src,
322 struct drm_property_info *info,
323 unsigned int num_infos,
324 drmModeObjectProperties *props)
325{
326 drmModePropertyRes *prop;
327 unsigned i, j;
328
329 for (i = 0; i < num_infos; i++) {
330 unsigned int j;
331
332 info[i].name = src[i].name;
333 info[i].prop_id = 0;
334 info[i].num_enum_values = src[i].num_enum_values;
335
336 if (src[i].num_enum_values == 0)
337 continue;
338
339 info[i].enum_values =
340 malloc(src[i].num_enum_values *
341 sizeof(*info[i].enum_values));
342 assert(info[i].enum_values);
343 for (j = 0; j < info[i].num_enum_values; j++) {
344 info[i].enum_values[j].name = src[i].enum_values[j].name;
345 info[i].enum_values[j].valid = false;
346 }
347 }
348
349 for (i = 0; i < props->count_props; i++) {
350 unsigned int k;
351
352 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
353 if (!prop)
354 continue;
355
356 for (j = 0; j < num_infos; j++) {
357 if (!strcmp(prop->name, info[j].name))
358 break;
359 }
360
361 /* We don't know/care about this property. */
362 if (j == num_infos) {
363#ifdef DEBUG
364 weston_log("DRM debug: unrecognized property %u '%s'\n",
365 prop->prop_id, prop->name);
366#endif
367 drmModeFreeProperty(prop);
368 continue;
369 }
370
371 if (info[j].num_enum_values == 0 &&
372 (prop->flags & DRM_MODE_PROP_ENUM)) {
373 weston_log("DRM: expected property %s to not be an"
374 " enum, but it is; ignoring\n", prop->name);
375 drmModeFreeProperty(prop);
376 continue;
377 }
378
379 info[j].prop_id = props->props[i];
380
381 if (info[j].num_enum_values == 0) {
382 drmModeFreeProperty(prop);
383 continue;
384 }
385
386 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
387 weston_log("DRM: expected property %s to be an enum,"
388 " but it is not; ignoring\n", prop->name);
389 drmModeFreeProperty(prop);
390 info[j].prop_id = 0;
391 continue;
392 }
393
394 for (k = 0; k < info[j].num_enum_values; k++) {
395 int l;
396
397 for (l = 0; l < prop->count_enums; l++) {
398 if (!strcmp(prop->enums[l].name,
399 info[j].enum_values[k].name))
400 break;
401 }
402
403 if (l == prop->count_enums)
404 continue;
405
406 info[j].enum_values[k].valid = true;
407 info[j].enum_values[k].value = prop->enums[l].value;
408 }
409
410 drmModeFreeProperty(prop);
411 }
412
413#ifdef DEBUG
414 for (i = 0; i < num_infos; i++) {
415 if (info[i].prop_id == 0)
416 weston_log("DRM warning: property '%s' missing\n",
417 info[i].name);
418 }
419#endif
420}
421
422/**
423 * Free DRM property information
424 *
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300425 * Frees all memory associated with a DRM property info array and zeroes
426 * it out, leaving it usable for a further drm_property_info_update() or
427 * drm_property_info_free().
Daniel Stone02cf4662017-03-03 16:19:39 +0000428 *
429 * @param info DRM property info array
430 * @param num_props Number of entries in array to free
431 */
432static void
433drm_property_info_free(struct drm_property_info *info, int num_props)
434{
435 int i;
436
437 for (i = 0; i < num_props; i++)
438 free(info[i].enum_values);
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300439
440 memset(info, 0, sizeof(*info) * num_props);
Daniel Stone02cf4662017-03-03 16:19:39 +0000441}
442
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400443static void
Daniel Stone2ba17f42015-05-19 20:02:41 +0100444drm_output_set_cursor(struct drm_output_state *output_state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400445
Mario Kleinerf507ec32015-06-21 21:25:14 +0200446static void
447drm_output_update_msc(struct drm_output *output, unsigned int seq);
448
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000449static void
450drm_output_destroy(struct weston_output *output_base);
451
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900452static void
453drm_virtual_output_destroy(struct weston_output *output_base);
454
Daniel Stone5ff289a2017-10-07 12:59:02 +0100455/**
456 * Returns true if the plane can be used on the given output for its current
457 * repaint cycle.
458 */
459static bool
460drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500461{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100462 assert(plane->state_cur);
463
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900464 if (output->virtual)
465 return false;
466
Daniel Stone5ff289a2017-10-07 12:59:02 +0100467 /* The plane still has a request not yet completed by the kernel. */
468 if (!plane->state_cur->complete)
469 return false;
470
471 /* The plane is still active on another output. */
472 if (plane->state_cur->output && plane->state_cur->output != output)
473 return false;
474
475 /* Check whether the plane can be used with this CRTC; possible_crtcs
476 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100477 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500478}
479
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000480static struct drm_output *
481drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
482{
483 struct drm_output *output;
484
485 wl_list_for_each(output, &b->compositor->output_list, base.link) {
486 if (output->crtc_id == crtc_id)
487 return output;
488 }
489
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000490 return NULL;
491}
492
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300493static struct drm_head *
494drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
495{
496 struct weston_head *base;
497 struct drm_head *head;
498
499 wl_list_for_each(base,
500 &backend->compositor->head_list, compositor_link) {
501 head = to_drm_head(base);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300502 if (head->connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300503 return head;
504 }
505
506 return NULL;
507}
508
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300509static void
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100510drm_fb_destroy(struct drm_fb *fb)
511{
512 if (fb->fb_id != 0)
513 drmModeRmFB(fb->fd, fb->fb_id);
514 weston_buffer_reference(&fb->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300515 weston_buffer_release_reference(&fb->buffer_release_ref, NULL);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100516 free(fb);
517}
518
519static void
520drm_fb_destroy_dumb(struct drm_fb *fb)
521{
522 struct drm_mode_destroy_dumb destroy_arg;
523
524 assert(fb->type == BUFFER_PIXMAN_DUMB);
525
526 if (fb->map && fb->size > 0)
527 munmap(fb->map, fb->size);
528
529 memset(&destroy_arg, 0, sizeof(destroy_arg));
Daniel Stone8eece0c2016-11-17 17:54:00 +0000530 destroy_arg.handle = fb->handles[0];
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100531 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
532
533 drm_fb_destroy(fb);
534}
535
536static void
537drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300538{
539 struct drm_fb *fb = data;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300540
Daniel Stonee4256832017-04-04 17:54:27 +0100541 assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
542 fb->type == BUFFER_CURSOR);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100543 drm_fb_destroy(fb);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300544}
545
Daniel Stone8eece0c2016-11-17 17:54:00 +0000546static int
Deepak Rawata864f582018-08-24 13:16:03 -0700547drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
Daniel Stone8eece0c2016-11-17 17:54:00 +0000548{
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000549 int ret = -EINVAL;
550#ifdef HAVE_DRM_ADDFB2_MODIFIERS
551 uint64_t mods[4] = { };
Daniel Stonedc082cb2018-07-09 13:49:04 +0100552 size_t i;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000553#endif
554
555 /* If we have a modifier set, we must only use the WithModifiers
556 * entrypoint; we cannot import it through legacy ioctls. */
Deepak Rawata864f582018-08-24 13:16:03 -0700557 if (b->fb_modifiers && fb->modifier != DRM_FORMAT_MOD_INVALID) {
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000558 /* KMS demands that if a modifier is set, it must be the same
559 * for all planes. */
560#ifdef HAVE_DRM_ADDFB2_MODIFIERS
Daniel Stonedc082cb2018-07-09 13:49:04 +0100561 for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++)
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000562 mods[i] = fb->modifier;
563 ret = drmModeAddFB2WithModifiers(fb->fd, fb->width, fb->height,
564 fb->format->format,
565 fb->handles, fb->strides,
566 fb->offsets, mods, &fb->fb_id,
567 DRM_MODE_FB_MODIFIERS);
568#endif
569 return ret;
570 }
Daniel Stone8eece0c2016-11-17 17:54:00 +0000571
572 ret = drmModeAddFB2(fb->fd, fb->width, fb->height, fb->format->format,
573 fb->handles, fb->strides, fb->offsets, &fb->fb_id,
574 0);
575 if (ret == 0)
576 return 0;
577
578 /* Legacy AddFB can't always infer the format from depth/bpp alone, so
579 * check if our format is one of the lucky ones. */
580 if (!fb->format->depth || !fb->format->bpp)
581 return ret;
582
583 /* Cannot fall back to AddFB for multi-planar formats either. */
584 if (fb->handles[1] || fb->handles[2] || fb->handles[3])
585 return ret;
586
587 ret = drmModeAddFB(fb->fd, fb->width, fb->height,
588 fb->format->depth, fb->format->bpp,
589 fb->strides[0], fb->handles[0], &fb->fb_id);
590 return ret;
591}
592
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300593static struct drm_fb *
Daniel Stonef214fdc2016-11-14 17:43:57 +0000594drm_fb_create_dumb(struct drm_backend *b, int width, int height,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300595 uint32_t format)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200596{
597 struct drm_fb *fb;
598 int ret;
599
600 struct drm_mode_create_dumb create_arg;
601 struct drm_mode_destroy_dumb destroy_arg;
602 struct drm_mode_map_dumb map_arg;
603
Peter Huttererf3d62272013-08-08 11:57:05 +1000604 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200605 if (!fb)
606 return NULL;
Daniel Stone6e7a9612017-04-04 17:54:26 +0100607 fb->refcnt = 1;
608
Daniel Stone0b70fa42017-04-04 17:54:23 +0100609 fb->format = pixel_format_get_info(format);
610 if (!fb->format) {
611 weston_log("failed to look up format 0x%lx\n",
612 (unsigned long) format);
613 goto err_fb;
614 }
615
616 if (!fb->format->depth || !fb->format->bpp) {
617 weston_log("format 0x%lx is not compatible with dumb buffers\n",
618 (unsigned long) format);
619 goto err_fb;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300620 }
621
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700622 memset(&create_arg, 0, sizeof create_arg);
Daniel Stone0b70fa42017-04-04 17:54:23 +0100623 create_arg.bpp = fb->format->bpp;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200624 create_arg.width = width;
625 create_arg.height = height;
626
Giulio Camuffo954f1832014-10-11 18:27:30 +0300627 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200628 if (ret)
629 goto err_fb;
630
Daniel Stonefc175a72017-04-04 17:54:22 +0100631 fb->type = BUFFER_PIXMAN_DUMB;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000632 fb->modifier = DRM_FORMAT_MOD_INVALID;
Daniel Stone8eece0c2016-11-17 17:54:00 +0000633 fb->handles[0] = create_arg.handle;
634 fb->strides[0] = create_arg.pitch;
Tomohito Esaki4976b092018-09-10 11:44:17 +0900635 fb->num_planes = 1;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200636 fb->size = create_arg.size;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000637 fb->width = width;
638 fb->height = height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300639 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200640
Deepak Rawata864f582018-08-24 13:16:03 -0700641 if (drm_fb_addfb(b, fb) != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200642 weston_log("failed to create kms fb: %s\n", strerror(errno));
Daniel Stone8eece0c2016-11-17 17:54:00 +0000643 goto err_bo;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300644 }
645
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700646 memset(&map_arg, 0, sizeof map_arg);
Daniel Stone8eece0c2016-11-17 17:54:00 +0000647 map_arg.handle = fb->handles[0];
Chris Michaeleb2074a2013-05-01 21:26:02 -0400648 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200649 if (ret)
650 goto err_add_fb;
651
Chris Michael4a7ce1f2015-11-10 10:40:37 -0500652 fb->map = mmap(NULL, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300653 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200654 if (fb->map == MAP_FAILED)
655 goto err_add_fb;
656
657 return fb;
658
659err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300660 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200661err_bo:
662 memset(&destroy_arg, 0, sizeof(destroy_arg));
663 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300664 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200665err_fb:
666 free(fb);
667 return NULL;
668}
669
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200670static struct drm_fb *
Daniel Stone6e7a9612017-04-04 17:54:26 +0100671drm_fb_ref(struct drm_fb *fb)
672{
673 fb->refcnt++;
674 return fb;
675}
676
Daniel Stonef522e222016-11-18 12:31:26 +0000677static void
678drm_fb_destroy_dmabuf(struct drm_fb *fb)
679{
680 /* We deliberately do not close the GEM handles here; GBM manages
681 * their lifetime through the BO. */
682 if (fb->bo)
683 gbm_bo_destroy(fb->bo);
684 drm_fb_destroy(fb);
685}
686
687static struct drm_fb *
688drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
689 struct drm_backend *backend, bool is_opaque)
690{
691#ifdef HAVE_GBM_FD_IMPORT
692 struct drm_fb *fb;
693 struct gbm_import_fd_data import_legacy = {
694 .width = dmabuf->attributes.width,
695 .height = dmabuf->attributes.height,
696 .format = dmabuf->attributes.format,
697 .stride = dmabuf->attributes.stride[0],
698 .fd = dmabuf->attributes.fd[0],
699 };
700 struct gbm_import_fd_modifier_data import_mod = {
701 .width = dmabuf->attributes.width,
702 .height = dmabuf->attributes.height,
703 .format = dmabuf->attributes.format,
704 .num_fds = dmabuf->attributes.n_planes,
705 .modifier = dmabuf->attributes.modifier[0],
706 };
707 int i;
708
709 /* XXX: TODO:
710 *
711 * Currently the buffer is rejected if any dmabuf attribute
712 * flag is set. This keeps us from passing an inverted /
713 * interlaced / bottom-first buffer (or any other type that may
714 * be added in the future) through to an overlay. Ultimately,
715 * these types of buffers should be handled through buffer
716 * transforms and not as spot-checks requiring specific
717 * knowledge. */
718 if (dmabuf->attributes.flags)
719 return NULL;
720
721 fb = zalloc(sizeof *fb);
722 if (fb == NULL)
723 return NULL;
724
725 fb->refcnt = 1;
726 fb->type = BUFFER_DMABUF;
727
728 static_assert(ARRAY_LENGTH(import_mod.fds) ==
729 ARRAY_LENGTH(dmabuf->attributes.fd),
730 "GBM and linux_dmabuf FD size must match");
731 static_assert(sizeof(import_mod.fds) == sizeof(dmabuf->attributes.fd),
732 "GBM and linux_dmabuf FD size must match");
733 memcpy(import_mod.fds, dmabuf->attributes.fd, sizeof(import_mod.fds));
734
735 static_assert(ARRAY_LENGTH(import_mod.strides) ==
736 ARRAY_LENGTH(dmabuf->attributes.stride),
737 "GBM and linux_dmabuf stride size must match");
738 static_assert(sizeof(import_mod.strides) ==
739 sizeof(dmabuf->attributes.stride),
740 "GBM and linux_dmabuf stride size must match");
741 memcpy(import_mod.strides, dmabuf->attributes.stride,
742 sizeof(import_mod.strides));
743
744 static_assert(ARRAY_LENGTH(import_mod.offsets) ==
745 ARRAY_LENGTH(dmabuf->attributes.offset),
746 "GBM and linux_dmabuf offset size must match");
747 static_assert(sizeof(import_mod.offsets) ==
748 sizeof(dmabuf->attributes.offset),
749 "GBM and linux_dmabuf offset size must match");
750 memcpy(import_mod.offsets, dmabuf->attributes.offset,
751 sizeof(import_mod.offsets));
752
753 /* The legacy FD-import path does not allow us to supply modifiers,
754 * multiple planes, or buffer offsets. */
755 if (dmabuf->attributes.modifier[0] != DRM_FORMAT_MOD_INVALID ||
756 import_mod.num_fds > 1 ||
757 import_mod.offsets[0] > 0) {
758 fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
759 &import_mod,
760 GBM_BO_USE_SCANOUT);
761 } else {
762 fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD,
763 &import_legacy,
764 GBM_BO_USE_SCANOUT);
765 }
766
767 if (!fb->bo)
768 goto err_free;
769
770 fb->width = dmabuf->attributes.width;
771 fb->height = dmabuf->attributes.height;
772 fb->modifier = dmabuf->attributes.modifier[0];
773 fb->size = 0;
774 fb->fd = backend->drm.fd;
775
776 static_assert(ARRAY_LENGTH(fb->strides) ==
777 ARRAY_LENGTH(dmabuf->attributes.stride),
778 "drm_fb and dmabuf stride size must match");
779 static_assert(sizeof(fb->strides) == sizeof(dmabuf->attributes.stride),
780 "drm_fb and dmabuf stride size must match");
781 memcpy(fb->strides, dmabuf->attributes.stride, sizeof(fb->strides));
782 static_assert(ARRAY_LENGTH(fb->offsets) ==
783 ARRAY_LENGTH(dmabuf->attributes.offset),
784 "drm_fb and dmabuf offset size must match");
785 static_assert(sizeof(fb->offsets) == sizeof(dmabuf->attributes.offset),
786 "drm_fb and dmabuf offset size must match");
787 memcpy(fb->offsets, dmabuf->attributes.offset, sizeof(fb->offsets));
788
789 fb->format = pixel_format_get_info(dmabuf->attributes.format);
790 if (!fb->format) {
791 weston_log("couldn't look up format info for 0x%lx\n",
792 (unsigned long) dmabuf->attributes.format);
793 goto err_free;
794 }
795
796 if (is_opaque)
797 fb->format = pixel_format_get_opaque_substitute(fb->format);
798
799 if (backend->min_width > fb->width ||
800 fb->width > backend->max_width ||
801 backend->min_height > fb->height ||
802 fb->height > backend->max_height) {
803 weston_log("bo geometry out of bounds\n");
804 goto err_free;
805 }
806
Tomohito Esaki4976b092018-09-10 11:44:17 +0900807 fb->num_planes = dmabuf->attributes.n_planes;
Daniel Stonef522e222016-11-18 12:31:26 +0000808 for (i = 0; i < dmabuf->attributes.n_planes; i++) {
Philipp Zabel1c49b542019-02-15 14:52:00 +0100809 union gbm_bo_handle handle;
810
811 handle = gbm_bo_get_handle_for_plane(fb->bo, i);
812 if (handle.s32 == -1)
Daniel Stonef522e222016-11-18 12:31:26 +0000813 goto err_free;
Philipp Zabel1c49b542019-02-15 14:52:00 +0100814 fb->handles[i] = handle.u32;
Daniel Stonef522e222016-11-18 12:31:26 +0000815 }
816
Deepak Rawata864f582018-08-24 13:16:03 -0700817 if (drm_fb_addfb(backend, fb) != 0)
Daniel Stonef522e222016-11-18 12:31:26 +0000818 goto err_free;
Daniel Stonef522e222016-11-18 12:31:26 +0000819
820 return fb;
821
822err_free:
823 drm_fb_destroy_dmabuf(fb);
824#endif
825 return NULL;
826}
827
Daniel Stone6e7a9612017-04-04 17:54:26 +0100828static struct drm_fb *
Daniel Stonefc175a72017-04-04 17:54:22 +0100829drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
Daniel Stonedb10df12016-12-08 13:15:58 +0000830 bool is_opaque, enum drm_fb_type type)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300831{
832 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Daniel Stone244244d2016-11-18 18:02:08 +0000833#ifdef HAVE_GBM_MODIFIERS
834 int i;
835#endif
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300836
Daniel Stonefc175a72017-04-04 17:54:22 +0100837 if (fb) {
838 assert(fb->type == type);
Daniel Stone6e7a9612017-04-04 17:54:26 +0100839 return drm_fb_ref(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +0100840 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300841
Bryce Harringtonde16d892014-11-20 22:21:57 -0800842 fb = zalloc(sizeof *fb);
843 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200844 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300845
Daniel Stonefc175a72017-04-04 17:54:22 +0100846 fb->type = type;
Daniel Stone6e7a9612017-04-04 17:54:26 +0100847 fb->refcnt = 1;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300848 fb->bo = bo;
Daniel Stone244244d2016-11-18 18:02:08 +0000849 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300850
Daniel Stonec8c917c2016-11-14 17:45:58 +0000851 fb->width = gbm_bo_get_width(bo);
852 fb->height = gbm_bo_get_height(bo);
Daniel Stone244244d2016-11-18 18:02:08 +0000853 fb->format = pixel_format_get_info(gbm_bo_get_format(bo));
854 fb->size = 0;
855
856#ifdef HAVE_GBM_MODIFIERS
857 fb->modifier = gbm_bo_get_modifier(bo);
Tomohito Esaki4976b092018-09-10 11:44:17 +0900858 fb->num_planes = gbm_bo_get_plane_count(bo);
859 for (i = 0; i < fb->num_planes; i++) {
Daniel Stone244244d2016-11-18 18:02:08 +0000860 fb->strides[i] = gbm_bo_get_stride_for_plane(bo, i);
861 fb->handles[i] = gbm_bo_get_handle_for_plane(bo, i).u32;
862 fb->offsets[i] = gbm_bo_get_offset(bo, i);
863 }
864#else
Tomohito Esaki4976b092018-09-10 11:44:17 +0900865 fb->num_planes = 1;
Daniel Stone8eece0c2016-11-17 17:54:00 +0000866 fb->strides[0] = gbm_bo_get_stride(bo);
867 fb->handles[0] = gbm_bo_get_handle(bo).u32;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000868 fb->modifier = DRM_FORMAT_MOD_INVALID;
Daniel Stone244244d2016-11-18 18:02:08 +0000869#endif
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300870
Daniel Stone0b70fa42017-04-04 17:54:23 +0100871 if (!fb->format) {
872 weston_log("couldn't look up format 0x%lx\n",
Daniel Stonedb10df12016-12-08 13:15:58 +0000873 (unsigned long) gbm_bo_get_format(bo));
Daniel Stone0b70fa42017-04-04 17:54:23 +0100874 goto err_free;
875 }
876
Daniel Stonedb10df12016-12-08 13:15:58 +0000877 /* We can scanout an ARGB buffer if the surface's opaque region covers
878 * the whole output, but we have to use XRGB as the KMS format code. */
879 if (is_opaque)
880 fb->format = pixel_format_get_opaque_substitute(fb->format);
881
Daniel Stonec8c917c2016-11-14 17:45:58 +0000882 if (backend->min_width > fb->width ||
883 fb->width > backend->max_width ||
884 backend->min_height > fb->height ||
885 fb->height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200886 weston_log("bo geometry out of bounds\n");
887 goto err_free;
888 }
889
Deepak Rawata864f582018-08-24 13:16:03 -0700890 if (drm_fb_addfb(backend, fb) != 0) {
Daniel Stone48687982018-07-12 12:16:47 +0100891 if (type == BUFFER_GBM_SURFACE)
Antonio Borneo39578632019-04-26 23:57:31 +0200892 weston_log("failed to create kms fb: %s\n",
893 strerror(errno));
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200894 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300895 }
896
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100897 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300898
899 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200900
901err_free:
902 free(fb);
903 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300904}
905
906static void
Alexandros Frantzis67629672018-10-19 12:14:11 +0300907drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer,
908 struct weston_buffer_release *buffer_release)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200909{
Pekka Paalanende685b82012-12-04 15:58:12 +0200910 assert(fb->buffer_ref.buffer == NULL);
Daniel Stonef522e222016-11-18 12:31:26 +0000911 assert(fb->type == BUFFER_CLIENT || fb->type == BUFFER_DMABUF);
Pekka Paalanende685b82012-12-04 15:58:12 +0200912 weston_buffer_reference(&fb->buffer_ref, buffer);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300913 weston_buffer_release_reference(&fb->buffer_release_ref,
914 buffer_release);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200915}
916
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200917static void
Daniel Stone05a5ac22017-04-04 17:54:25 +0100918drm_fb_unref(struct drm_fb *fb)
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200919{
920 if (!fb)
921 return;
922
Daniel Stone6e7a9612017-04-04 17:54:26 +0100923 assert(fb->refcnt > 0);
924 if (--fb->refcnt > 0)
925 return;
926
Daniel Stonefc175a72017-04-04 17:54:22 +0100927 switch (fb->type) {
928 case BUFFER_PIXMAN_DUMB:
Daniel Stone6e7a9612017-04-04 17:54:26 +0100929 drm_fb_destroy_dumb(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +0100930 break;
Daniel Stonee4256832017-04-04 17:54:27 +0100931 case BUFFER_CURSOR:
Daniel Stonefc175a72017-04-04 17:54:22 +0100932 case BUFFER_CLIENT:
933 gbm_bo_destroy(fb->bo);
934 break;
935 case BUFFER_GBM_SURFACE:
Daniel Stone05a5ac22017-04-04 17:54:25 +0100936 gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
Daniel Stonefc175a72017-04-04 17:54:22 +0100937 break;
Daniel Stonef522e222016-11-18 12:31:26 +0000938 case BUFFER_DMABUF:
939 drm_fb_destroy_dmabuf(fb);
940 break;
Daniel Stonefc175a72017-04-04 17:54:22 +0100941 default:
942 assert(NULL);
943 break;
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200944 }
945}
946
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000947/**
Daniel Stonebc15f682016-11-14 16:57:01 +0000948 * Allocate a new, empty, plane state.
949 */
950static struct drm_plane_state *
951drm_plane_state_alloc(struct drm_output_state *state_output,
952 struct drm_plane *plane)
953{
954 struct drm_plane_state *state = zalloc(sizeof(*state));
955
956 assert(state);
957 state->output_state = state_output;
958 state->plane = plane;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300959 state->in_fence_fd = -1;
Deepak Rawat009b3cf2018-07-24 14:05:37 -0700960 pixman_region32_init(&state->damage);
Daniel Stonebc15f682016-11-14 16:57:01 +0000961
962 /* Here we only add the plane state to the desired link, and not
963 * set the member. Having an output pointer set means that the
964 * plane will be displayed on the output; this won't be the case
965 * when we go to disable a plane. In this case, it must be part of
966 * the commit (and thus the output state), but the member must be
967 * NULL, as it will not be on any output when the state takes
968 * effect.
969 */
970 if (state_output)
971 wl_list_insert(&state_output->plane_list, &state->link);
972 else
973 wl_list_init(&state->link);
974
975 return state;
976}
977
978/**
979 * Free an existing plane state. As a special case, the state will not
980 * normally be freed if it is the current state; see drm_plane_set_state.
981 */
982static void
983drm_plane_state_free(struct drm_plane_state *state, bool force)
984{
985 if (!state)
986 return;
987
988 wl_list_remove(&state->link);
989 wl_list_init(&state->link);
990 state->output_state = NULL;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300991 state->in_fence_fd = -1;
Deepak Rawat009b3cf2018-07-24 14:05:37 -0700992 pixman_region32_fini(&state->damage);
Daniel Stonebc15f682016-11-14 16:57:01 +0000993
994 if (force || state != state->plane->state_cur) {
995 drm_fb_unref(state->fb);
996 free(state);
997 }
998}
999
1000/**
1001 * Duplicate an existing plane state into a new plane state, storing it within
1002 * the given output state. If the output state already contains a plane state
1003 * for the drm_plane referenced by 'src', that plane state is freed first.
1004 */
1005static struct drm_plane_state *
1006drm_plane_state_duplicate(struct drm_output_state *state_output,
1007 struct drm_plane_state *src)
1008{
1009 struct drm_plane_state *dst = malloc(sizeof(*dst));
1010 struct drm_plane_state *old, *tmp;
1011
1012 assert(src);
1013 assert(dst);
1014 *dst = *src;
1015 wl_list_init(&dst->link);
1016
1017 wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
1018 /* Duplicating a plane state into the same output state, so
1019 * it can replace itself with an identical copy of itself,
1020 * makes no sense. */
1021 assert(old != src);
1022 if (old->plane == dst->plane)
1023 drm_plane_state_free(old, false);
1024 }
1025
1026 wl_list_insert(&state_output->plane_list, &dst->link);
1027 if (src->fb)
1028 dst->fb = drm_fb_ref(src->fb);
1029 dst->output_state = state_output;
Deepak Rawat009b3cf2018-07-24 14:05:37 -07001030 pixman_region32_init(&dst->damage);
Daniel Stonebc15f682016-11-14 16:57:01 +00001031 dst->complete = false;
1032
1033 return dst;
1034}
1035
1036/**
1037 * Remove a plane state from an output state; if the plane was previously
1038 * enabled, then replace it with a disabling state. This ensures that the
1039 * output state was untouched from it was before the plane state was
1040 * modified by the caller of this function.
1041 *
1042 * This is required as drm_output_state_get_plane may either allocate a
1043 * new plane state, in which case this function will just perform a matching
1044 * drm_plane_state_free, or it may instead repurpose an existing disabling
1045 * state (if the plane was previously active), in which case this function
1046 * will reset it.
1047 */
1048static void
1049drm_plane_state_put_back(struct drm_plane_state *state)
1050{
1051 struct drm_output_state *state_output;
1052 struct drm_plane *plane;
1053
1054 if (!state)
1055 return;
1056
1057 state_output = state->output_state;
1058 plane = state->plane;
1059 drm_plane_state_free(state, false);
1060
1061 /* Plane was previously disabled; no need to keep this temporary
1062 * state around. */
1063 if (!plane->state_cur->fb)
1064 return;
1065
1066 (void) drm_plane_state_alloc(state_output, plane);
1067}
1068
Daniel Stonece137472016-11-16 19:35:03 +00001069static bool
1070drm_view_transform_supported(struct weston_view *ev, struct weston_output *output)
1071{
1072 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
1073
1074 /* This will incorrectly disallow cases where the combination of
1075 * buffer and view transformations match the output transform.
1076 * Fixing this requires a full analysis of the transformation
1077 * chain. */
1078 if (ev->transform.enabled &&
1079 ev->transform.matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE)
1080 return false;
1081
1082 if (viewport->buffer.transform != output->transform)
1083 return false;
1084
1085 return true;
1086}
1087
Daniel Stonebc15f682016-11-14 16:57:01 +00001088/**
Daniel Stoned6e2a762016-11-16 19:33:20 +00001089 * Given a weston_view, fill the drm_plane_state's co-ordinates to display on
1090 * a given plane.
1091 */
Daniel Stonece137472016-11-16 19:35:03 +00001092static bool
Daniel Stoned6e2a762016-11-16 19:33:20 +00001093drm_plane_state_coords_for_view(struct drm_plane_state *state,
1094 struct weston_view *ev)
1095{
1096 struct drm_output *output = state->output;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001097 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001098 pixman_region32_t dest_rect, src_rect;
1099 pixman_box32_t *box, tbox;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001100 float sxf1, syf1, sxf2, syf2;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001101
Daniel Stonece137472016-11-16 19:35:03 +00001102 if (!drm_view_transform_supported(ev, &output->base))
1103 return false;
1104
Daniel Stoned6e2a762016-11-16 19:33:20 +00001105 /* Update the base weston_plane co-ordinates. */
1106 box = pixman_region32_extents(&ev->transform.boundingbox);
1107 state->plane->base.x = box->x1;
1108 state->plane->base.y = box->y1;
1109
1110 /* First calculate the destination co-ordinates by taking the
1111 * area of the view which is visible on this output, performing any
1112 * transforms to account for output rotation and scale as necessary. */
1113 pixman_region32_init(&dest_rect);
1114 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
1115 &output->base.region);
1116 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
1117 box = pixman_region32_extents(&dest_rect);
1118 tbox = weston_transformed_rect(output->base.width,
1119 output->base.height,
1120 output->base.transform,
1121 output->base.current_scale,
1122 *box);
1123 state->dest_x = tbox.x1;
1124 state->dest_y = tbox.y1;
1125 state->dest_w = tbox.x2 - tbox.x1;
1126 state->dest_h = tbox.y2 - tbox.y1;
1127 pixman_region32_fini(&dest_rect);
1128
1129 /* Now calculate the source rectangle, by finding the extents of the
1130 * view, and working backwards to source co-ordinates. */
1131 pixman_region32_init(&src_rect);
1132 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
1133 &output->base.region);
1134 box = pixman_region32_extents(&src_rect);
Daniel Stonedf2726a2017-02-07 18:48:19 +00001135 weston_view_from_global_float(ev, box->x1, box->y1, &sxf1, &syf1);
1136 weston_surface_to_buffer_float(ev->surface, sxf1, syf1, &sxf1, &syf1);
1137 weston_view_from_global_float(ev, box->x2, box->y2, &sxf2, &syf2);
1138 weston_surface_to_buffer_float(ev->surface, sxf2, syf2, &sxf2, &syf2);
1139 pixman_region32_fini(&src_rect);
Daniel Stoned6e2a762016-11-16 19:33:20 +00001140
Daniel Stonedf2726a2017-02-07 18:48:19 +00001141 /* Buffer transforms may mean that x2 is to the left of x1, and/or that
1142 * y2 is above y1. */
1143 if (sxf2 < sxf1) {
1144 double tmp = sxf1;
1145 sxf1 = sxf2;
1146 sxf2 = tmp;
1147 }
1148 if (syf2 < syf1) {
1149 double tmp = syf1;
1150 syf1 = syf2;
1151 syf2 = tmp;
1152 }
1153
1154 /* Shift from S23.8 wl_fixed to U16.16 KMS fixed-point encoding. */
1155 state->src_x = wl_fixed_from_double(sxf1) << 8;
1156 state->src_y = wl_fixed_from_double(syf1) << 8;
1157 state->src_w = wl_fixed_from_double(sxf2 - sxf1) << 8;
1158 state->src_h = wl_fixed_from_double(syf2 - syf1) << 8;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001159
1160 /* Clamp our source co-ordinates to surface bounds; it's possible
1161 * for intermediate translations to give us slightly incorrect
1162 * co-ordinates if we have, for example, multiple zooming
1163 * transformations. View bounding boxes are also explicitly rounded
1164 * greedily. */
Daniel Stonedf2726a2017-02-07 18:48:19 +00001165 if (state->src_x < 0)
1166 state->src_x = 0;
1167 if (state->src_y < 0)
1168 state->src_y = 0;
1169 if (state->src_w > (uint32_t) ((buffer->width << 16) - state->src_x))
1170 state->src_w = (buffer->width << 16) - state->src_x;
1171 if (state->src_h > (uint32_t) ((buffer->height << 16) - state->src_y))
1172 state->src_h = (buffer->height << 16) - state->src_y;
Daniel Stonece137472016-11-16 19:35:03 +00001173
1174 return true;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001175}
1176
Daniel Stonef11ec022016-11-17 17:32:42 +00001177static struct drm_fb *
1178drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
1179{
1180 struct drm_output *output = state->output;
1181 struct drm_backend *b = to_drm_backend(output->base.compositor);
1182 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Philipp Zabelfff27972018-09-03 20:13:52 +02001183 bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox);
Daniel Stonef11ec022016-11-17 17:32:42 +00001184 struct linux_dmabuf_buffer *dmabuf;
1185 struct drm_fb *fb;
Daniel Stonef11ec022016-11-17 17:32:42 +00001186
Daniel Stonef11ec022016-11-17 17:32:42 +00001187 if (ev->alpha != 1.0f)
1188 return NULL;
1189
1190 if (!drm_view_transform_supported(ev, &output->base))
1191 return NULL;
1192
1193 if (!buffer)
1194 return NULL;
1195
1196 if (wl_shm_buffer_get(buffer->resource))
1197 return NULL;
1198
Daniel Stonef522e222016-11-18 12:31:26 +00001199 /* GBM is used for dmabuf import as well as from client wl_buffer. */
Daniel Stonef11ec022016-11-17 17:32:42 +00001200 if (!b->gbm)
1201 return NULL;
1202
1203 dmabuf = linux_dmabuf_buffer_get(buffer->resource);
1204 if (dmabuf) {
Daniel Stonef522e222016-11-18 12:31:26 +00001205 fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque);
1206 if (!fb)
Daniel Stonef11ec022016-11-17 17:32:42 +00001207 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00001208 } else {
Daniel Stonef522e222016-11-18 12:31:26 +00001209 struct gbm_bo *bo;
1210
Daniel Stonef11ec022016-11-17 17:32:42 +00001211 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
1212 buffer->resource, GBM_BO_USE_SCANOUT);
Daniel Stonef522e222016-11-18 12:31:26 +00001213 if (!bo)
1214 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00001215
Daniel Stonef522e222016-11-18 12:31:26 +00001216 fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT);
1217 if (!fb) {
1218 gbm_bo_destroy(bo);
1219 return NULL;
1220 }
Daniel Stonef11ec022016-11-17 17:32:42 +00001221 }
1222
Marius Vladf5ca2f12019-01-22 17:56:36 +02001223 drm_debug(b, "\t\t\t[view] view %p format: %s\n",
1224 ev, fb->format->drm_format_name);
Alexandros Frantzis67629672018-10-19 12:14:11 +03001225 drm_fb_set_buffer(fb, buffer,
1226 ev->surface->buffer_release_ref.buffer_release);
Daniel Stonef11ec022016-11-17 17:32:42 +00001227 return fb;
1228}
1229
Daniel Stoned6e2a762016-11-16 19:33:20 +00001230/**
Daniel Stone2ba17f42015-05-19 20:02:41 +01001231 * Return a plane state from a drm_output_state.
1232 */
1233static struct drm_plane_state *
1234drm_output_state_get_existing_plane(struct drm_output_state *state_output,
1235 struct drm_plane *plane)
1236{
1237 struct drm_plane_state *ps;
1238
1239 wl_list_for_each(ps, &state_output->plane_list, link) {
1240 if (ps->plane == plane)
1241 return ps;
1242 }
1243
1244 return NULL;
1245}
1246
1247/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001248 * Return a plane state from a drm_output_state, either existing or
1249 * freshly allocated.
1250 */
1251static struct drm_plane_state *
1252drm_output_state_get_plane(struct drm_output_state *state_output,
1253 struct drm_plane *plane)
1254{
1255 struct drm_plane_state *ps;
1256
Daniel Stone2ba17f42015-05-19 20:02:41 +01001257 ps = drm_output_state_get_existing_plane(state_output, plane);
1258 if (ps)
1259 return ps;
Daniel Stonebc15f682016-11-14 16:57:01 +00001260
1261 return drm_plane_state_alloc(state_output, plane);
1262}
1263
1264/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001265 * Allocate a new, empty drm_output_state. This should not generally be used
1266 * in the repaint cycle; see drm_output_state_duplicate.
1267 */
1268static struct drm_output_state *
1269drm_output_state_alloc(struct drm_output *output,
1270 struct drm_pending_state *pending_state)
Daniel Stone90648872016-10-21 18:08:37 +01001271{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001272 struct drm_output_state *state = zalloc(sizeof(*state));
1273
1274 assert(state);
1275 state->output = output;
Daniel Stonea08512f2016-11-08 17:46:10 +00001276 state->dpms = WESTON_DPMS_OFF;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001277 state->pending_state = pending_state;
1278 if (pending_state)
1279 wl_list_insert(&pending_state->output_list, &state->link);
1280 else
1281 wl_list_init(&state->link);
1282
Daniel Stonebc15f682016-11-14 16:57:01 +00001283 wl_list_init(&state->plane_list);
1284
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001285 return state;
1286}
1287
1288/**
1289 * Duplicate an existing drm_output_state into a new one. This is generally
1290 * used during the repaint cycle, to capture the existing state of an output
1291 * and modify it to create a new state to be used.
1292 *
1293 * The mode determines whether the output will be reset to an a blank state,
1294 * or an exact mirror of the current state.
1295 */
1296static struct drm_output_state *
1297drm_output_state_duplicate(struct drm_output_state *src,
1298 struct drm_pending_state *pending_state,
1299 enum drm_output_state_duplicate_mode plane_mode)
1300{
1301 struct drm_output_state *dst = malloc(sizeof(*dst));
Daniel Stonebc15f682016-11-14 16:57:01 +00001302 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001303
1304 assert(dst);
1305
1306 /* Copy the whole structure, then individually modify the
1307 * pending_state, as well as the list link into our pending
1308 * state. */
1309 *dst = *src;
1310
1311 dst->pending_state = pending_state;
1312 if (pending_state)
1313 wl_list_insert(&pending_state->output_list, &dst->link);
1314 else
1315 wl_list_init(&dst->link);
1316
Daniel Stonebc15f682016-11-14 16:57:01 +00001317 wl_list_init(&dst->plane_list);
1318
1319 wl_list_for_each(ps, &src->plane_list, link) {
1320 /* Don't carry planes which are now disabled; these should be
1321 * free for other outputs to reuse. */
1322 if (!ps->output)
1323 continue;
1324
1325 if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
1326 (void) drm_plane_state_alloc(dst, ps->plane);
1327 else
1328 (void) drm_plane_state_duplicate(dst, ps);
1329 }
1330
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001331 return dst;
1332}
1333
1334/**
1335 * Free an unused drm_output_state.
1336 */
1337static void
1338drm_output_state_free(struct drm_output_state *state)
1339{
Daniel Stonebc15f682016-11-14 16:57:01 +00001340 struct drm_plane_state *ps, *next;
1341
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001342 if (!state)
1343 return;
1344
Daniel Stonebc15f682016-11-14 16:57:01 +00001345 wl_list_for_each_safe(ps, next, &state->plane_list, link)
1346 drm_plane_state_free(ps, false);
1347
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001348 wl_list_remove(&state->link);
Daniel Stonebc15f682016-11-14 16:57:01 +00001349
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001350 free(state);
Daniel Stone90648872016-10-21 18:08:37 +01001351}
1352
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001353/**
Daniel Stonea08512f2016-11-08 17:46:10 +00001354 * Get output state to disable output
1355 *
1356 * Returns a pointer to an output_state object which can be used to disable
1357 * an output (e.g. DPMS off).
1358 *
1359 * @param pending_state The pending state object owning this update
1360 * @param output The output to disable
1361 * @returns A drm_output_state to disable the output
1362 */
1363static struct drm_output_state *
1364drm_output_get_disable_state(struct drm_pending_state *pending_state,
1365 struct drm_output *output)
1366{
1367 struct drm_output_state *output_state;
1368
1369 output_state = drm_output_state_duplicate(output->state_cur,
1370 pending_state,
1371 DRM_OUTPUT_STATE_CLEAR_PLANES);
1372 output_state->dpms = WESTON_DPMS_OFF;
1373
1374 return output_state;
1375}
1376
1377/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001378 * Allocate a new drm_pending_state
1379 *
1380 * Allocate a new, empty, 'pending state' structure to be used across a
1381 * repaint cycle or similar.
1382 *
1383 * @param backend DRM backend
1384 * @returns Newly-allocated pending state structure
1385 */
1386static struct drm_pending_state *
1387drm_pending_state_alloc(struct drm_backend *backend)
1388{
1389 struct drm_pending_state *ret;
1390
1391 ret = calloc(1, sizeof(*ret));
1392 if (!ret)
1393 return NULL;
1394
1395 ret->backend = backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001396 wl_list_init(&ret->output_list);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001397
1398 return ret;
1399}
1400
1401/**
1402 * Free a drm_pending_state structure
1403 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001404 * Frees a pending_state structure, as well as any output_states connected
1405 * to this pending state.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001406 *
1407 * @param pending_state Pending state structure to free
1408 */
1409static void
1410drm_pending_state_free(struct drm_pending_state *pending_state)
1411{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001412 struct drm_output_state *output_state, *tmp;
1413
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001414 if (!pending_state)
1415 return;
1416
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001417 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1418 link) {
1419 drm_output_state_free(output_state);
1420 }
1421
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001422 free(pending_state);
1423}
1424
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001425/**
1426 * Find an output state in a pending state
1427 *
1428 * Given a pending_state structure, find the output_state for a particular
1429 * output.
1430 *
1431 * @param pending_state Pending state structure to search
1432 * @param output Output to find state for
1433 * @returns Output state if present, or NULL if not
1434 */
1435static struct drm_output_state *
1436drm_pending_state_get_output(struct drm_pending_state *pending_state,
1437 struct drm_output *output)
1438{
1439 struct drm_output_state *output_state;
1440
1441 wl_list_for_each(output_state, &pending_state->output_list, link) {
1442 if (output_state->output == output)
1443 return output_state;
1444 }
1445
1446 return NULL;
1447}
1448
Daniel Stonea08512f2016-11-08 17:46:10 +00001449static int drm_pending_state_apply_sync(struct drm_pending_state *state);
Daniel Stonebb6c19f2016-12-08 17:27:17 +00001450static int drm_pending_state_test(struct drm_pending_state *state);
Daniel Stonea08512f2016-11-08 17:46:10 +00001451
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001452/**
1453 * Mark a drm_output_state (the output's last state) as complete. This handles
1454 * any post-completion actions such as updating the repaint timer, disabling the
1455 * output, and finally freeing the state.
1456 */
1457static void
1458drm_output_update_complete(struct drm_output *output, uint32_t flags,
1459 unsigned int sec, unsigned int usec)
1460{
Daniel Stonea08512f2016-11-08 17:46:10 +00001461 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001462 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001463 struct timespec ts;
1464
1465 /* Stop the pageflip timer instead of rearming it here */
1466 if (output->pageflip_timer)
1467 wl_event_source_timer_update(output->pageflip_timer, 0);
1468
Daniel Stonebc15f682016-11-14 16:57:01 +00001469 wl_list_for_each(ps, &output->state_cur->plane_list, link)
1470 ps->complete = true;
1471
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001472 drm_output_state_free(output->state_last);
1473 output->state_last = NULL;
1474
1475 if (output->destroy_pending) {
Daniel Stonea08512f2016-11-08 17:46:10 +00001476 output->destroy_pending = 0;
1477 output->disable_pending = 0;
1478 output->dpms_off_pending = 0;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001479 drm_output_destroy(&output->base);
1480 return;
1481 } else if (output->disable_pending) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001482 output->disable_pending = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00001483 output->dpms_off_pending = 0;
1484 weston_output_disable(&output->base);
1485 return;
1486 } else if (output->dpms_off_pending) {
1487 struct drm_pending_state *pending = drm_pending_state_alloc(b);
1488 output->dpms_off_pending = 0;
1489 drm_output_get_disable_state(pending, output);
1490 drm_pending_state_apply_sync(pending);
Daniel Stonea08512f2016-11-08 17:46:10 +00001491 } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
1492 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
1493 /* DPMS can happen to us either in the middle of a repaint
1494 * cycle (when we have painted fresh content, only to throw it
1495 * away for DPMS off), or at any other random point. If the
1496 * latter is true, then we cannot go through finish_frame,
1497 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001498 return;
1499 }
1500
1501 ts.tv_sec = sec;
1502 ts.tv_nsec = usec * 1000;
1503 weston_output_finish_frame(&output->base, &ts, flags);
1504
1505 /* We can't call this from frame_notify, because the output's
1506 * repaint needed flag is cleared just after that */
1507 if (output->recorder)
1508 weston_output_schedule_repaint(&output->base);
1509}
1510
1511/**
1512 * Mark an output state as current on the output, i.e. it has been
1513 * submitted to the kernel. The mode argument determines whether this
1514 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
1515 * or asynchronously (in which case we wait for events to complete).
1516 */
1517static void
1518drm_output_assign_state(struct drm_output_state *state,
1519 enum drm_state_apply_mode mode)
1520{
1521 struct drm_output *output = state->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00001522 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001523 struct drm_plane_state *plane_state;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001524
1525 assert(!output->state_last);
1526
1527 if (mode == DRM_STATE_APPLY_ASYNC)
1528 output->state_last = output->state_cur;
1529 else
1530 drm_output_state_free(output->state_cur);
1531
1532 wl_list_remove(&state->link);
1533 wl_list_init(&state->link);
1534 state->pending_state = NULL;
1535
1536 output->state_cur = state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001537
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03001538 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
1539 drm_debug(b, "\t[CRTC:%u] setting pending flip\n", output->crtc_id);
Daniel Stone598ee9d2016-11-16 11:55:20 +00001540 output->atomic_complete_pending = 1;
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03001541 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00001542
Daniel Stonebc15f682016-11-14 16:57:01 +00001543 /* Replace state_cur on each affected plane with the new state, being
1544 * careful to dispose of orphaned (but only orphaned) previous state.
1545 * If the previous state is not orphaned (still has an output_state
1546 * attached), it will be disposed of by freeing the output_state. */
1547 wl_list_for_each(plane_state, &state->plane_list, link) {
1548 struct drm_plane *plane = plane_state->plane;
1549
1550 if (plane->state_cur && !plane->state_cur->output_state)
1551 drm_plane_state_free(plane->state_cur, true);
1552 plane->state_cur = plane_state;
1553
1554 if (mode != DRM_STATE_APPLY_ASYNC) {
1555 plane_state->complete = true;
1556 continue;
1557 }
1558
Daniel Stone598ee9d2016-11-16 11:55:20 +00001559 if (b->atomic_modeset)
1560 continue;
1561
Daniel Stone31838bf2019-06-17 11:23:25 +01001562 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
1563 if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
Daniel Stonee2e80132018-01-16 15:37:33 +00001564 output->page_flip_pending = 1;
Daniel Stonebc15f682016-11-14 16:57:01 +00001565 }
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001566}
1567
Daniel Stonef8290622016-12-09 17:32:10 +00001568static struct drm_plane_state *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001569drm_output_prepare_scanout_view(struct drm_output_state *output_state,
Daniel Stonea284d272018-07-10 18:40:12 +01001570 struct weston_view *ev,
1571 enum drm_output_propose_state_mode mode)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001572{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001573 struct drm_output *output = output_state->output;
Daniel Stone44abfaa2018-07-10 14:31:06 +01001574 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001575 struct drm_plane *scanout_plane = output->scanout_plane;
1576 struct drm_plane_state *state;
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001577 struct drm_fb *fb;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001578 pixman_box32_t *extents;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001579
Daniel Stone44abfaa2018-07-10 14:31:06 +01001580 assert(!b->sprites_are_broken);
Daniel Stone87fab1c2019-06-17 11:13:20 +01001581 assert(b->atomic_modeset);
Daniel Stonea284d272018-07-10 18:40:12 +01001582 assert(mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
Daniel Stone44abfaa2018-07-10 14:31:06 +01001583
Daniel Stone7cdf2312016-11-16 19:40:29 +00001584 /* Check the view spans exactly the output size, calculated in the
1585 * logical co-ordinate space. */
1586 extents = pixman_region32_extents(&ev->transform.boundingbox);
1587 if (extents->x1 != output->base.x ||
1588 extents->y1 != output->base.y ||
1589 extents->x2 != output->base.x + output->base.width ||
1590 extents->y2 != output->base.y + output->base.height)
Daniel Stone90648872016-10-21 18:08:37 +01001591 return NULL;
1592
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03001593 /* If the surface buffer has an in-fence fd, but the plane doesn't
1594 * support fences, we can't place the buffer on this plane. */
1595 if (ev->surface->acquire_fence_fd >= 0 &&
Daniel Stone87fab1c2019-06-17 11:13:20 +01001596 scanout_plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0)
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03001597 return NULL;
1598
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001599 fb = drm_fb_get_from_view(output_state, ev);
Marius Vlad748f09e2018-12-18 10:29:20 +02001600 if (!fb) {
1601 drm_debug(b, "\t\t\t\t[scanout] not placing view %p on scanout: "
1602 " couldn't get fb\n", ev);
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001603 return NULL;
Marius Vlad748f09e2018-12-18 10:29:20 +02001604 }
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001605
Daniel Stonee2e80132018-01-16 15:37:33 +00001606 state = drm_output_state_get_plane(output_state, scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +00001607
Daniel Stonea284d272018-07-10 18:40:12 +01001608 /* The only way we can already have a buffer in the scanout plane is
1609 * if we are in mixed mode, or if a client buffer has already been
1610 * placed into scanout. The former case will never call into here,
1611 * and in the latter case, the view must have been marked as occluded,
1612 * meaning we should never have ended up here. */
1613 assert(!state->fb);
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001614 state->fb = fb;
Daniel Stoneee1aea72017-12-18 13:41:09 +00001615 state->ev = ev;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001616 state->output = output;
1617 if (!drm_plane_state_coords_for_view(state, ev))
1618 goto err;
1619
Daniel Stone9fe4bf82016-12-09 18:23:22 +00001620 if (state->dest_x != 0 || state->dest_y != 0 ||
Daniel Stone7cdf2312016-11-16 19:40:29 +00001621 state->dest_w != (unsigned) output->base.current_mode->width ||
1622 state->dest_h != (unsigned) output->base.current_mode->height)
1623 goto err;
1624
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03001625 state->in_fence_fd = ev->surface->acquire_fence_fd;
1626
Daniel Stonea284d272018-07-10 18:40:12 +01001627 /* In plane-only mode, we don't need to test the state now, as we
1628 * will only test it once at the end. */
Daniel Stonef8290622016-12-09 17:32:10 +00001629 return state;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001630
1631err:
1632 drm_plane_state_put_back(state);
1633 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001634}
1635
Daniel Stone95d48a22017-04-04 17:54:30 +01001636static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001637drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001638{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001639 struct drm_output *output = state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02001640 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001641 struct gbm_bo *bo;
Daniel Stone95d48a22017-04-04 17:54:30 +01001642 struct drm_fb *ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001643
Giulio Camuffo954f1832014-10-11 18:27:30 +03001644 output->base.compositor->renderer->repaint_output(&output->base,
1645 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001646
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001647 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001648 if (!bo) {
Antonio Borneo39578632019-04-26 23:57:31 +02001649 weston_log("failed to lock front buffer: %s\n",
1650 strerror(errno));
Daniel Stone95d48a22017-04-04 17:54:30 +01001651 return NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001652 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001653
Daniel Stonedb10df12016-12-08 13:15:58 +00001654 /* The renderer always produces an opaque image. */
1655 ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE);
Daniel Stone95d48a22017-04-04 17:54:30 +01001656 if (!ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001657 weston_log("failed to get drm_fb for bo\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001658 gbm_surface_release_buffer(output->gbm_surface, bo);
Daniel Stone95d48a22017-04-04 17:54:30 +01001659 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001660 }
Daniel Stone95d48a22017-04-04 17:54:30 +01001661 ret->gbm_surface = output->gbm_surface;
1662
1663 return ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001664}
1665
Daniel Stone95d48a22017-04-04 17:54:30 +01001666static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001667drm_output_render_pixman(struct drm_output_state *state,
1668 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001669{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001670 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001671 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001672
1673 output->current_image ^= 1;
1674
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001675 pixman_renderer_output_set_buffer(&output->base,
1676 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001677 pixman_renderer_output_set_hw_extra_damage(&output->base,
1678 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001679
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001680 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001681
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001682 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +01001683
1684 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001685}
1686
1687static void
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001688drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001689{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001690 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001691 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +00001692 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +00001693 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02001694 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +01001695 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001696
Daniel Stone4e84f7d2017-04-04 17:54:29 +01001697 /* If we already have a client buffer promoted to scanout, then we don't
1698 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +00001699 scanout_state = drm_output_state_get_plane(state,
1700 output->scanout_plane);
1701 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +01001702 return;
1703
Daniel Stonee95169b2016-11-14 17:46:59 +00001704 if (!pixman_region32_not_empty(damage) &&
1705 scanout_plane->state_cur->fb &&
1706 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
1707 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
1708 scanout_plane->state_cur->fb->width ==
1709 output->base.current_mode->width &&
1710 scanout_plane->state_cur->fb->height ==
1711 output->base.current_mode->height) {
1712 fb = drm_fb_ref(scanout_plane->state_cur->fb);
1713 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001714 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00001715 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001716 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00001717 }
Daniel Stone95d48a22017-04-04 17:54:30 +01001718
Daniel Stonee2e80132018-01-16 15:37:33 +00001719 if (!fb) {
1720 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +01001721 return;
Daniel Stonee2e80132018-01-16 15:37:33 +00001722 }
1723
1724 scanout_state->fb = fb;
1725 scanout_state->output = output;
1726
1727 scanout_state->src_x = 0;
1728 scanout_state->src_y = 0;
1729 scanout_state->src_w = output->base.current_mode->width << 16;
1730 scanout_state->src_h = output->base.current_mode->height << 16;
1731
1732 scanout_state->dest_x = 0;
1733 scanout_state->dest_y = 0;
1734 scanout_state->dest_w = scanout_state->src_w >> 16;
1735 scanout_state->dest_h = scanout_state->src_h >> 16;
1736
Deepak Rawat46a1c722018-07-24 14:13:34 -07001737 pixman_region32_copy(&scanout_state->damage, damage);
1738 if (output->base.zoom.active) {
1739 weston_matrix_transform_region(&scanout_state->damage,
1740 &output->base.matrix,
1741 &scanout_state->damage);
1742 } else {
1743 pixman_region32_translate(&scanout_state->damage,
1744 -output->base.x, -output->base.y);
1745 weston_transformed_region(output->base.width,
1746 output->base.height,
1747 output->base.transform,
1748 output->base.current_scale,
1749 &scanout_state->damage,
1750 &scanout_state->damage);
1751 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001752
Giulio Camuffo954f1832014-10-11 18:27:30 +03001753 pixman_region32_subtract(&c->primary_plane.damage,
1754 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001755}
1756
1757static void
Richard Hughese7299962013-05-01 21:52:12 +01001758drm_output_set_gamma(struct weston_output *output_base,
1759 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
1760{
1761 int rc;
Armin Krezović545dba62016-08-05 15:54:18 +02001762 struct drm_output *output = to_drm_output(output_base);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001763 struct drm_backend *backend =
Armin Krezović545dba62016-08-05 15:54:18 +02001764 to_drm_backend(output->base.compositor);
Richard Hughese7299962013-05-01 21:52:12 +01001765
1766 /* check */
1767 if (output_base->gamma_size != size)
1768 return;
Richard Hughese7299962013-05-01 21:52:12 +01001769
Giulio Camuffo954f1832014-10-11 18:27:30 +03001770 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +01001771 output->crtc_id,
1772 size, r, g, b);
1773 if (rc)
Antonio Borneo39578632019-04-26 23:57:31 +02001774 weston_log("set gamma failed: %s\n", strerror(errno));
Richard Hughese7299962013-05-01 21:52:12 +01001775}
1776
Bryce Harringtonada4f072015-06-30 13:25:46 -07001777/* Determine the type of vblank synchronization to use for the output.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001778 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07001779 * The pipe parameter indicates which CRTC is in use. Knowing this, we
1780 * can determine which vblank sequence type to use for it. Traditional
1781 * cards had only two CRTCs, with CRTC 0 using no special flags, and
1782 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
1783 * parameter indicates this.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001784 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07001785 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
1786 * 0-31. If this is non-zero it indicates we're dealing with a
1787 * multi-gpu situation and we need to calculate the vblank sync
1788 * using DRM_BLANK_HIGH_CRTC_MASK.
1789 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +03001790static unsigned int
1791drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02001792{
1793 if (output->pipe > 1)
1794 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
1795 DRM_VBLANK_HIGH_CRTC_MASK;
1796 else if (output->pipe > 0)
1797 return DRM_VBLANK_SECONDARY;
1798 else
1799 return 0;
1800}
1801
David Herrmann1edf44c2013-10-22 17:11:26 +02001802static int
Daniel Stone598ee9d2016-11-16 11:55:20 +00001803drm_output_apply_state_legacy(struct drm_output_state *state)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001804{
Daniel Stonea08512f2016-11-08 17:46:10 +00001805 struct drm_output *output = state->output;
1806 struct drm_backend *backend = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001807 struct drm_plane *scanout_plane = output->scanout_plane;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001808 struct drm_property_info *dpms_prop;
Daniel Stonee2e80132018-01-16 15:37:33 +00001809 struct drm_plane_state *scanout_state;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001810 struct drm_mode *mode;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001811 struct drm_head *head;
Marius Vlad1ca025c2019-01-09 12:26:07 +02001812 const struct pixel_format_info *pinfo = NULL;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001813 uint32_t connectors[MAX_CLONED_CONNECTORS];
1814 int n_conn = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00001815 struct timespec now;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001816 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001817
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001818 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1819 assert(n_conn < MAX_CLONED_CONNECTORS);
1820 connectors[n_conn++] = head->connector_id;
1821 }
1822
Derek Foreman2cd87fe2017-04-13 13:48:48 -05001823 /* If disable_planes is set then assign_planes() wasn't
1824 * called for this render, so we could still have a stale
1825 * cursor plane set up.
1826 */
1827 if (output->base.disable_planes) {
1828 output->cursor_view = NULL;
Greg V1f781762018-02-19 17:59:42 +03001829 if (output->cursor_plane) {
1830 output->cursor_plane->base.x = INT32_MIN;
1831 output->cursor_plane->base.y = INT32_MIN;
1832 }
Derek Foreman2cd87fe2017-04-13 13:48:48 -05001833 }
1834
Daniel Stonea08512f2016-11-08 17:46:10 +00001835 if (state->dpms != WESTON_DPMS_ON) {
Daniel Stonea08512f2016-11-08 17:46:10 +00001836 if (output->cursor_plane) {
1837 ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
1838 0, 0, 0);
1839 if (ret)
Antonio Borneo39578632019-04-26 23:57:31 +02001840 weston_log("drmModeSetCursor failed disable: %s\n",
1841 strerror(errno));
Daniel Stonea08512f2016-11-08 17:46:10 +00001842 }
1843
1844 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001845 NULL, 0, NULL);
Daniel Stonea08512f2016-11-08 17:46:10 +00001846 if (ret)
Antonio Borneo39578632019-04-26 23:57:31 +02001847 weston_log("drmModeSetCrtc failed disabling: %s\n",
1848 strerror(errno));
Daniel Stonea08512f2016-11-08 17:46:10 +00001849
1850 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
1851 weston_compositor_read_presentation_clock(output->base.compositor, &now);
1852 drm_output_update_complete(output,
1853 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
1854 now.tv_sec, now.tv_nsec / 1000);
1855
1856 return 0;
1857 }
1858
1859 scanout_state =
1860 drm_output_state_get_existing_plane(state, scanout_plane);
Daniel Stone087ddf02017-02-14 17:51:30 +00001861
Daniel Stonee2e80132018-01-16 15:37:33 +00001862 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
1863 * legacy PageFlip API doesn't allow us to do clipping either. */
1864 assert(scanout_state->src_x == 0);
1865 assert(scanout_state->src_y == 0);
1866 assert(scanout_state->src_w ==
1867 (unsigned) (output->base.current_mode->width << 16));
1868 assert(scanout_state->src_h ==
1869 (unsigned) (output->base.current_mode->height << 16));
1870 assert(scanout_state->dest_x == 0);
1871 assert(scanout_state->dest_y == 0);
1872 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
1873 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03001874 /* The legacy SetCrtc API doesn't support fences */
1875 assert(scanout_state->in_fence_fd == -1);
Daniel Stonee2e80132018-01-16 15:37:33 +00001876
Daniel Stonecb04cc42016-11-16 11:51:27 +00001877 mode = to_drm_mode(output->base.current_mode);
Daniel Stone8eece0c2016-11-17 17:54:00 +00001878 if (backend->state_invalid ||
1879 !scanout_plane->state_cur->fb ||
1880 scanout_plane->state_cur->fb->strides[0] !=
1881 scanout_state->fb->strides[0]) {
Marius Vlad1ca025c2019-01-09 12:26:07 +02001882
Giulio Camuffo954f1832014-10-11 18:27:30 +03001883 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00001884 scanout_state->fb->fb_id,
1885 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001886 connectors, n_conn,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001887 &mode->mode_info);
1888 if (ret) {
Antonio Borneo39578632019-04-26 23:57:31 +02001889 weston_log("set mode failed: %s\n", strerror(errno));
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001890 goto err;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001891 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02001892 }
1893
Marius Vlad1ca025c2019-01-09 12:26:07 +02001894 pinfo = scanout_state->fb->format;
1895 drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
1896 output->crtc_id, scanout_state->plane->plane_id,
1897 pinfo ? pinfo->drm_format_name : "UNKNOWN");
1898
Giulio Camuffo954f1832014-10-11 18:27:30 +03001899 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00001900 scanout_state->fb->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05001901 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02001902 weston_log("queueing pageflip failed: %s\n", strerror(errno));
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001903 goto err;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05001904 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01001905
Daniel Stone205c0a02017-04-04 17:54:33 +01001906 assert(!output->page_flip_pending);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03001907
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001908 if (output->pageflip_timer)
1909 wl_event_source_timer_update(output->pageflip_timer,
1910 backend->pageflip_timeout);
1911
Daniel Stone2ba17f42015-05-19 20:02:41 +01001912 drm_output_set_cursor(state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001913
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001914 if (state->dpms != output->state_cur->dpms) {
1915 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1916 dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
1917 if (dpms_prop->prop_id == 0)
1918 continue;
1919
1920 ret = drmModeConnectorSetProperty(backend->drm.fd,
1921 head->connector_id,
1922 dpms_prop->prop_id,
1923 state->dpms);
1924 if (ret) {
1925 weston_log("DRM: DPMS: failed property set for %s\n",
1926 head->base.name);
1927 }
Daniel Stonea08512f2016-11-08 17:46:10 +00001928 }
1929 }
1930
1931 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
1932
David Herrmann1edf44c2013-10-22 17:11:26 +02001933 return 0;
1934
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001935err:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -08001936 output->cursor_view = NULL;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001937 drm_output_state_free(state);
Daniel Stonea08512f2016-11-08 17:46:10 +00001938 return -1;
1939}
David Herrmann1edf44c2013-10-22 17:11:26 +02001940
Daniel Stone598ee9d2016-11-16 11:55:20 +00001941#ifdef HAVE_DRM_ATOMIC
1942static int
1943crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
1944 enum wdrm_crtc_property prop, uint64_t val)
1945{
1946 struct drm_property_info *info = &output->props_crtc[prop];
1947 int ret;
1948
1949 if (info->prop_id == 0)
1950 return -1;
1951
1952 ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
1953 val);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01001954 drm_debug(output->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
1955 (unsigned long) output->crtc_id,
1956 (unsigned long) info->prop_id, info->name,
1957 (unsigned long long) val, (unsigned long long) val);
Daniel Stone598ee9d2016-11-16 11:55:20 +00001958 return (ret <= 0) ? -1 : 0;
1959}
1960
1961static int
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001962connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
Daniel Stone598ee9d2016-11-16 11:55:20 +00001963 enum wdrm_connector_property prop, uint64_t val)
1964{
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001965 struct drm_property_info *info = &head->props_conn[prop];
Daniel Stone598ee9d2016-11-16 11:55:20 +00001966 int ret;
1967
1968 if (info->prop_id == 0)
1969 return -1;
1970
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001971 ret = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00001972 info->prop_id, val);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01001973 drm_debug(head->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
1974 (unsigned long) head->connector_id,
1975 (unsigned long) info->prop_id, info->name,
1976 (unsigned long long) val, (unsigned long long) val);
Daniel Stone598ee9d2016-11-16 11:55:20 +00001977 return (ret <= 0) ? -1 : 0;
1978}
1979
1980static int
1981plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
1982 enum wdrm_plane_property prop, uint64_t val)
1983{
1984 struct drm_property_info *info = &plane->props[prop];
1985 int ret;
1986
1987 if (info->prop_id == 0)
1988 return -1;
1989
1990 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
1991 val);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01001992 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
1993 (unsigned long) plane->plane_id,
1994 (unsigned long) info->prop_id, info->name,
1995 (unsigned long long) val, (unsigned long long) val);
Daniel Stone598ee9d2016-11-16 11:55:20 +00001996 return (ret <= 0) ? -1 : 0;
1997}
1998
1999static int
2000drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
2001{
2002 int ret;
2003
2004 if (mode->blob_id)
2005 return 0;
2006
2007 ret = drmModeCreatePropertyBlob(backend->drm.fd,
2008 &mode->mode_info,
2009 sizeof(mode->mode_info),
2010 &mode->blob_id);
2011 if (ret != 0)
Antonio Borneo39578632019-04-26 23:57:31 +02002012 weston_log("failed to create mode property blob: %s\n",
2013 strerror(errno));
Daniel Stone598ee9d2016-11-16 11:55:20 +00002014
Daniel Stone2914a6d2019-02-16 16:16:10 +00002015 drm_debug(backend, "\t\t\t[atomic] created new mode blob %lu for %s\n",
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002016 (unsigned long) mode->blob_id, mode->mode_info.name);
2017
Daniel Stone598ee9d2016-11-16 11:55:20 +00002018 return ret;
2019}
2020
2021static int
Deepak Rawat009b3cf2018-07-24 14:05:37 -07002022plane_add_damage(drmModeAtomicReq *req, struct drm_backend *backend,
2023 struct drm_plane_state *plane_state)
2024{
2025 struct drm_plane *plane = plane_state->plane;
2026 struct drm_property_info *info =
2027 &plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
2028 pixman_box32_t *rects;
2029 uint32_t blob_id;
2030 int n_rects;
2031 int ret;
2032
2033 if (!pixman_region32_not_empty(&plane_state->damage))
2034 return 0;
2035
2036 /*
2037 * If a plane doesn't support fb damage blob property, kernel will
2038 * perform full plane update.
2039 */
2040 if (info->prop_id == 0)
2041 return 0;
2042
2043 rects = pixman_region32_rectangles(&plane_state->damage, &n_rects);
2044
2045 ret = drmModeCreatePropertyBlob(backend->drm.fd, rects,
2046 sizeof(*rects) * n_rects, &blob_id);
2047 if (ret != 0)
2048 return ret;
2049
2050 ret = plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS, blob_id);
2051 if (ret != 0)
2052 return ret;
2053
2054 return 0;
2055}
2056
2057static int
Daniel Stone598ee9d2016-11-16 11:55:20 +00002058drm_output_apply_state_atomic(struct drm_output_state *state,
2059 drmModeAtomicReq *req,
2060 uint32_t *flags)
2061{
2062 struct drm_output *output = state->output;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002063 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002064 struct drm_plane_state *plane_state;
2065 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002066 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002067 int ret = 0;
2068
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002069 drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
2070 (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
2071 (unsigned long) output->base.id, output->base.name);
2072
2073 if (state->dpms != output->state_cur->dpms) {
2074 drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
Daniel Stone598ee9d2016-11-16 11:55:20 +00002075 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002076 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00002077
2078 if (state->dpms == WESTON_DPMS_ON) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002079 ret = drm_mode_ensure_blob(b, current_mode);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002080 if (ret != 0)
2081 return ret;
2082
2083 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
2084 current_mode->blob_id);
2085 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002086
Daniel Stone76255772018-07-06 11:36:49 +01002087 /* No need for the DPMS property, since it is implicit in
2088 * routing and CRTC activity. */
Pekka Paalanen2f661302017-09-12 16:07:32 +03002089 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2090 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
2091 output->crtc_id);
2092 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00002093 } else {
2094 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
2095 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002096
Daniel Stone76255772018-07-06 11:36:49 +01002097 /* No need for the DPMS property, since it is implicit in
2098 * routing and CRTC activity. */
Pekka Paalanen2f661302017-09-12 16:07:32 +03002099 wl_list_for_each(head, &output->base.head_list, base.output_link)
2100 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002101 }
2102
2103 if (ret != 0) {
2104 weston_log("couldn't set atomic CRTC/connector state\n");
2105 return ret;
2106 }
2107
2108 wl_list_for_each(plane_state, &state->plane_list, link) {
2109 struct drm_plane *plane = plane_state->plane;
Marius Vlad1ca025c2019-01-09 12:26:07 +02002110 const struct pixel_format_info *pinfo = NULL;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002111
2112 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
2113 plane_state->fb ? plane_state->fb->fb_id : 0);
2114 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
2115 plane_state->fb ? output->crtc_id : 0);
2116 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
2117 plane_state->src_x);
2118 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
2119 plane_state->src_y);
2120 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
2121 plane_state->src_w);
2122 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
2123 plane_state->src_h);
2124 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
2125 plane_state->dest_x);
2126 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
2127 plane_state->dest_y);
2128 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
2129 plane_state->dest_w);
2130 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
2131 plane_state->dest_h);
Deepak Rawat009b3cf2018-07-24 14:05:37 -07002132 ret |= plane_add_damage(req, b, plane_state);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002133
Marius Vlad1ca025c2019-01-09 12:26:07 +02002134 if (plane_state->fb && plane_state->fb->format)
2135 pinfo = plane_state->fb->format;
2136
2137 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
2138 (unsigned long) plane->plane_id,
2139 pinfo ? pinfo->drm_format_name : "UNKNOWN");
2140
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002141 if (plane_state->in_fence_fd >= 0) {
2142 ret |= plane_add_prop(req, plane,
2143 WDRM_PLANE_IN_FENCE_FD,
2144 plane_state->in_fence_fd);
2145 }
2146
Daniel Stone598ee9d2016-11-16 11:55:20 +00002147 if (ret != 0) {
2148 weston_log("couldn't set plane state\n");
2149 return ret;
2150 }
2151 }
2152
2153 return 0;
2154}
2155
2156/**
2157 * Helper function used only by drm_pending_state_apply, with the same
2158 * guarantees and constraints as that function.
2159 */
2160static int
2161drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
2162 enum drm_state_apply_mode mode)
2163{
2164 struct drm_backend *b = pending_state->backend;
2165 struct drm_output_state *output_state, *tmp;
2166 struct drm_plane *plane;
2167 drmModeAtomicReq *req = drmModeAtomicAlloc();
Daniel Stone3158a2d2018-07-20 19:35:05 +01002168 uint32_t flags;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002169 int ret = 0;
2170
2171 if (!req)
2172 return -1;
2173
Daniel Stone3158a2d2018-07-20 19:35:05 +01002174 switch (mode) {
2175 case DRM_STATE_APPLY_SYNC:
2176 flags = 0;
2177 break;
2178 case DRM_STATE_APPLY_ASYNC:
2179 flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
2180 break;
2181 case DRM_STATE_TEST_ONLY:
2182 flags = DRM_MODE_ATOMIC_TEST_ONLY;
2183 break;
2184 }
2185
Daniel Stone598ee9d2016-11-16 11:55:20 +00002186 if (b->state_invalid) {
Pekka Paalaneneacec812017-09-12 13:43:51 +03002187 struct weston_head *head_base;
2188 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002189 uint32_t *unused;
2190 int err;
2191
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002192 drm_debug(b, "\t\t[atomic] previous state invalid; "
2193 "starting with fresh state\n");
2194
Daniel Stone598ee9d2016-11-16 11:55:20 +00002195 /* If we need to reset all our state (e.g. because we've
2196 * just started, or just been VT-switched in), explicitly
2197 * disable all the CRTCs and connectors we aren't using. */
Pekka Paalaneneacec812017-09-12 13:43:51 +03002198 wl_list_for_each(head_base,
2199 &b->compositor->head_list, compositor_link) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00002200 struct drm_property_info *info;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002201
Pekka Paalaneneacec812017-09-12 13:43:51 +03002202 if (weston_head_is_enabled(head_base))
Daniel Stone598ee9d2016-11-16 11:55:20 +00002203 continue;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002204
Pekka Paalaneneacec812017-09-12 13:43:51 +03002205 head = to_drm_head(head_base);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002206
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002207 drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
2208 head_base->name);
2209
Pekka Paalaneneacec812017-09-12 13:43:51 +03002210 info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
2211 err = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002212 info->prop_id, 0);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002213 drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
2214 (unsigned long) head->connector_id,
2215 (unsigned long) info->prop_id,
2216 info->name);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002217 if (err <= 0)
2218 ret = -1;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002219 }
2220
2221 wl_array_for_each(unused, &b->unused_crtcs) {
2222 struct drm_property_info infos[WDRM_CRTC__COUNT];
2223 struct drm_property_info *info;
2224 drmModeObjectProperties *props;
2225 uint64_t active;
2226
2227 memset(infos, 0, sizeof(infos));
2228
2229 /* We can't emit a disable on a CRTC that's already
2230 * off, as the kernel will refuse to generate an event
2231 * for an off->off state and fail the commit.
2232 */
2233 props = drmModeObjectGetProperties(b->drm.fd,
2234 *unused,
2235 DRM_MODE_OBJECT_CRTC);
2236 if (!props) {
2237 ret = -1;
2238 continue;
2239 }
2240
2241 drm_property_info_populate(b, crtc_props, infos,
2242 WDRM_CRTC__COUNT,
2243 props);
2244
2245 info = &infos[WDRM_CRTC_ACTIVE];
2246 active = drm_property_get_value(info, props, 0);
2247 drmModeFreeObjectProperties(props);
2248 if (active == 0) {
2249 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2250 continue;
2251 }
2252
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002253 drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
2254 (unsigned long) *unused);
2255
2256 drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
2257 (unsigned long) *unused,
2258 (unsigned long) info->prop_id, info->name);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002259 err = drmModeAtomicAddProperty(req, *unused,
2260 info->prop_id, 0);
2261 if (err <= 0)
2262 ret = -1;
2263
2264 info = &infos[WDRM_CRTC_MODE_ID];
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002265 drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
2266 (unsigned long) *unused,
2267 (unsigned long) info->prop_id, info->name);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002268 err = drmModeAtomicAddProperty(req, *unused,
2269 info->prop_id, 0);
2270 if (err <= 0)
2271 ret = -1;
2272
2273 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2274 }
2275
2276 /* Disable all the planes; planes which are being used will
2277 * override this state in the output-state application. */
2278 wl_list_for_each(plane, &b->plane_list, link) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002279 drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
2280 (unsigned long) plane->plane_id);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002281 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
2282 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
2283 }
2284
2285 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2286 }
2287
2288 wl_list_for_each(output_state, &pending_state->output_list, link) {
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002289 if (output_state->output->virtual)
2290 continue;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002291 if (mode == DRM_STATE_APPLY_SYNC)
2292 assert(output_state->dpms == WESTON_DPMS_OFF);
2293 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
2294 }
2295
2296 if (ret != 0) {
2297 weston_log("atomic: couldn't compile atomic state\n");
2298 goto out;
2299 }
2300
Daniel Stone598ee9d2016-11-16 11:55:20 +00002301 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03002302 drm_debug(b, "[atomic] drmModeAtomicCommit\n");
Daniel Stonebb6c19f2016-12-08 17:27:17 +00002303
2304 /* Test commits do not take ownership of the state; return
2305 * without freeing here. */
2306 if (mode == DRM_STATE_TEST_ONLY) {
2307 drmModeAtomicFree(req);
2308 return ret;
2309 }
2310
Daniel Stone598ee9d2016-11-16 11:55:20 +00002311 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002312 weston_log("atomic: couldn't commit new state: %s\n",
2313 strerror(errno));
Daniel Stone598ee9d2016-11-16 11:55:20 +00002314 goto out;
2315 }
2316
2317 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2318 link)
2319 drm_output_assign_state(output_state, mode);
2320
2321 b->state_invalid = false;
2322
2323 assert(wl_list_empty(&pending_state->output_list));
2324
2325out:
2326 drmModeAtomicFree(req);
2327 drm_pending_state_free(pending_state);
2328 return ret;
2329}
2330#endif
2331
Daniel Stonea08512f2016-11-08 17:46:10 +00002332/**
Daniel Stonebb6c19f2016-12-08 17:27:17 +00002333 * Tests a pending state, to see if the kernel will accept the update as
2334 * constructed.
2335 *
2336 * Using atomic modesetting, the kernel performs the same checks as it would
2337 * on a real commit, returning success or failure without actually modifying
2338 * the running state. It does not return -EBUSY if there are pending updates
2339 * in flight, so states may be tested at any point, however this means a
2340 * state which passed testing may fail on a real commit if the timing is not
2341 * respected (e.g. committing before the previous commit has completed).
2342 *
2343 * Without atomic modesetting, we have no way to check, so we optimistically
2344 * claim it will work.
2345 *
2346 * Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
2347 * function does _not_ take ownership of pending_state, nor does it clear
2348 * state_invalid.
2349 */
2350static int
2351drm_pending_state_test(struct drm_pending_state *pending_state)
2352{
2353#ifdef HAVE_DRM_ATOMIC
2354 struct drm_backend *b = pending_state->backend;
2355
2356 if (b->atomic_modeset)
2357 return drm_pending_state_apply_atomic(pending_state,
2358 DRM_STATE_TEST_ONLY);
2359#endif
2360
2361 /* We have no way to test state before application on the legacy
2362 * modesetting API, so just claim it succeeded. */
2363 return 0;
2364}
2365
2366/**
Daniel Stonea08512f2016-11-08 17:46:10 +00002367 * Applies all of a pending_state asynchronously: the primary entry point for
2368 * applying KMS state to a device. Updates the state for all outputs in the
2369 * pending_state, as well as disabling any unclaimed outputs.
2370 *
2371 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2372 */
2373static int
2374drm_pending_state_apply(struct drm_pending_state *pending_state)
2375{
2376 struct drm_backend *b = pending_state->backend;
2377 struct drm_output_state *output_state, *tmp;
2378 uint32_t *unused;
2379
Daniel Stone598ee9d2016-11-16 11:55:20 +00002380#ifdef HAVE_DRM_ATOMIC
2381 if (b->atomic_modeset)
2382 return drm_pending_state_apply_atomic(pending_state,
2383 DRM_STATE_APPLY_ASYNC);
2384#endif
2385
Daniel Stonea08512f2016-11-08 17:46:10 +00002386 if (b->state_invalid) {
2387 /* If we need to reset all our state (e.g. because we've
2388 * just started, or just been VT-switched in), explicitly
2389 * disable all the CRTCs we aren't using. This also disables
2390 * all connectors on these CRTCs, so we don't need to do that
2391 * separately with the pre-atomic API. */
2392 wl_array_for_each(unused, &b->unused_crtcs)
2393 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2394 NULL);
2395 }
2396
2397 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2398 link) {
2399 struct drm_output *output = output_state->output;
2400 int ret;
2401
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002402 if (output->virtual) {
2403 drm_output_assign_state(output_state,
2404 DRM_STATE_APPLY_ASYNC);
2405 continue;
2406 }
2407
Daniel Stone598ee9d2016-11-16 11:55:20 +00002408 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002409 if (ret != 0) {
2410 weston_log("Couldn't apply state for output %s\n",
2411 output->base.name);
2412 }
2413 }
2414
2415 b->state_invalid = false;
2416
2417 assert(wl_list_empty(&pending_state->output_list));
2418
2419 drm_pending_state_free(pending_state);
2420
2421 return 0;
2422}
2423
2424/**
2425 * The synchronous version of drm_pending_state_apply. May only be used to
2426 * disable outputs. Does so synchronously: the request is guaranteed to have
2427 * completed on return, and the output will not be touched afterwards.
2428 *
2429 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2430 */
2431static int
2432drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
2433{
2434 struct drm_backend *b = pending_state->backend;
2435 struct drm_output_state *output_state, *tmp;
2436 uint32_t *unused;
2437
Daniel Stone598ee9d2016-11-16 11:55:20 +00002438#ifdef HAVE_DRM_ATOMIC
2439 if (b->atomic_modeset)
2440 return drm_pending_state_apply_atomic(pending_state,
2441 DRM_STATE_APPLY_SYNC);
2442#endif
2443
Daniel Stonea08512f2016-11-08 17:46:10 +00002444 if (b->state_invalid) {
2445 /* If we need to reset all our state (e.g. because we've
2446 * just started, or just been VT-switched in), explicitly
2447 * disable all the CRTCs we aren't using. This also disables
2448 * all connectors on these CRTCs, so we don't need to do that
2449 * separately with the pre-atomic API. */
2450 wl_array_for_each(unused, &b->unused_crtcs)
2451 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2452 NULL);
2453 }
2454
2455 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2456 link) {
2457 int ret;
2458
2459 assert(output_state->dpms == WESTON_DPMS_OFF);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002460 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002461 if (ret != 0) {
2462 weston_log("Couldn't apply state for output %s\n",
2463 output_state->output->base.name);
2464 }
2465 }
2466
2467 b->state_invalid = false;
2468
2469 assert(wl_list_empty(&pending_state->output_list));
2470
2471 drm_pending_state_free(pending_state);
2472
2473 return 0;
2474}
2475
2476static int
2477drm_output_repaint(struct weston_output *output_base,
2478 pixman_region32_t *damage,
2479 void *repaint_data)
2480{
2481 struct drm_pending_state *pending_state = repaint_data;
2482 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00002483 struct drm_output_state *state = NULL;
2484 struct drm_plane_state *scanout_state;
2485
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002486 assert(!output->virtual);
2487
Daniel Stonea08512f2016-11-08 17:46:10 +00002488 if (output->disable_pending || output->destroy_pending)
2489 goto err;
2490
2491 assert(!output->state_last);
2492
2493 /* If planes have been disabled in the core, we might not have
2494 * hit assign_planes at all, so might not have valid output state
2495 * here. */
2496 state = drm_pending_state_get_output(pending_state, output);
2497 if (!state)
2498 state = drm_output_state_duplicate(output->state_cur,
2499 pending_state,
2500 DRM_OUTPUT_STATE_CLEAR_PLANES);
2501 state->dpms = WESTON_DPMS_ON;
2502
2503 drm_output_render(state, damage);
2504 scanout_state = drm_output_state_get_plane(state,
2505 output->scanout_plane);
2506 if (!scanout_state || !scanout_state->fb)
2507 goto err;
2508
Daniel Stonea08512f2016-11-08 17:46:10 +00002509 return 0;
2510
2511err:
2512 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +02002513 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002514}
2515
2516static void
Jonas Ådahle5a12252013-04-05 23:07:11 +02002517drm_output_start_repaint_loop(struct weston_output *output_base)
2518{
Armin Krezović545dba62016-08-05 15:54:18 +02002519 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +00002520 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +00002521 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02002522 struct drm_backend *backend =
2523 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002524 struct timespec ts, tnow;
2525 struct timespec vbl2now;
2526 int64_t refresh_nsec;
2527 int ret;
2528 drmVBlank vbl = {
2529 .request.type = DRM_VBLANK_RELATIVE,
2530 .request.sequence = 0,
2531 .request.signal = 0,
2532 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002533
Armin Krezović08368132016-09-30 14:11:05 +02002534 if (output->disable_pending || output->destroy_pending)
Xiong Zhangabd5d472013-10-11 14:43:07 +08002535 return;
2536
Daniel Stonee2e80132018-01-16 15:37:33 +00002537 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002538 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +02002539 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002540 }
2541
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002542 /* Need to smash all state in from scratch; current timings might not
2543 * be what we want, page flip might not work, etc.
2544 */
Daniel Stone6020f472018-02-05 15:46:20 +00002545 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002546 goto finish_frame;
2547
Daniel Stonee2e80132018-01-16 15:37:33 +00002548 assert(scanout_plane->state_cur->output == output);
2549
Mario Kleinerf507ec32015-06-21 21:25:14 +02002550 /* Try to get current msc and timestamp via instant query */
2551 vbl.request.type |= drm_waitvblank_pipe(output);
2552 ret = drmWaitVBlank(backend->drm.fd, &vbl);
2553
2554 /* Error ret or zero timestamp means failure to get valid timestamp */
2555 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
2556 ts.tv_sec = vbl.reply.tval_sec;
2557 ts.tv_nsec = vbl.reply.tval_usec * 1000;
2558
2559 /* Valid timestamp for most recent vblank - not stale?
2560 * Stale ts could happen on Linux 3.17+, so make sure it
2561 * is not older than 1 refresh duration since now.
2562 */
2563 weston_compositor_read_presentation_clock(backend->compositor,
2564 &tnow);
2565 timespec_sub(&vbl2now, &tnow, &ts);
2566 refresh_nsec =
2567 millihz_to_nsec(output->base.current_mode->refresh);
2568 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
2569 drm_output_update_msc(output, vbl.reply.sequence);
2570 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002571 WP_PRESENTATION_FEEDBACK_INVALID);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002572 return;
2573 }
2574 }
2575
2576 /* Immediate query didn't provide valid timestamp.
2577 * Use pageflip fallback.
2578 */
Jonas Ådahle5a12252013-04-05 23:07:11 +02002579
Daniel Stone205c0a02017-04-04 17:54:33 +01002580 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002581 assert(!output->state_last);
2582
2583 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +00002584 drm_output_state_duplicate(output->state_cur, pending_state,
2585 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +01002586
Daniel Stone8747f952016-11-29 20:17:32 +00002587 ret = drm_pending_state_apply(pending_state);
2588 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002589 weston_log("applying repaint-start state failed: %s\n",
2590 strerror(errno));
David Herrmann3c688c52013-10-22 17:11:25 +02002591 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +02002592 }
David Herrmann3c688c52013-10-22 17:11:25 +02002593
2594 return;
2595
2596finish_frame:
2597 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +00002598 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002599 WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002600}
2601
2602static void
Pekka Paalanen641307c2014-09-23 22:08:47 -04002603drm_output_update_msc(struct drm_output *output, unsigned int seq)
2604{
2605 uint64_t msc_hi = output->base.msc >> 32;
2606
2607 if (seq < (output->base.msc & 0xffffffff))
2608 msc_hi++;
2609
2610 output->base.msc = (msc_hi << 32) + seq;
2611}
2612
Jesse Barnes58ef3792012-02-23 09:45:49 -05002613
2614static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002615page_flip_handler(int fd, unsigned int frame,
2616 unsigned int sec, unsigned int usec, void *data)
2617{
Armin Krezović545dba62016-08-05 15:54:18 +02002618 struct drm_output *output = data;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002619 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002620 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2621 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2622 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002623
Pekka Paalanen641307c2014-09-23 22:08:47 -04002624 drm_output_update_msc(output, frame);
2625
Daniel Stone598ee9d2016-11-16 11:55:20 +00002626 assert(!b->atomic_modeset);
Daniel Stone205c0a02017-04-04 17:54:33 +01002627 assert(output->page_flip_pending);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002628 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002629
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002630 drm_output_update_complete(output, flags, sec, usec);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002631}
2632
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002633/**
2634 * Begin a new repaint cycle
2635 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002636 * Called by the core compositor at the beginning of a repaint cycle. Creates
2637 * a new pending_state structure to own any output state created by individual
2638 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002639 */
2640static void *
2641drm_repaint_begin(struct weston_compositor *compositor)
2642{
2643 struct drm_backend *b = to_drm_backend(compositor);
2644 struct drm_pending_state *ret;
2645
2646 ret = drm_pending_state_alloc(b);
2647 b->repaint_data = ret;
2648
Marius Vlad7e4db952019-04-17 13:47:06 +03002649 if (weston_log_scope_is_enabled(b->debug)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002650 char *dbg = weston_compositor_print_scene_graph(compositor);
2651 drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
2652 ret);
2653 drm_debug(b, "%s", dbg);
2654 free(dbg);
2655 }
2656
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002657 return ret;
2658}
2659
2660/**
2661 * Flush a repaint set
2662 *
2663 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002664 * and should be flushed. Frees the pending state, transitioning ownership
2665 * of the output state from the pending state, to the update itself. When
2666 * the update completes (see drm_output_update_complete), the output
2667 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002668 */
2669static void
2670drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
2671{
2672 struct drm_backend *b = to_drm_backend(compositor);
2673 struct drm_pending_state *pending_state = repaint_data;
Daniel Stone6020f472018-02-05 15:46:20 +00002674
Daniel Stonea08512f2016-11-08 17:46:10 +00002675 drm_pending_state_apply(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002676 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002677 b->repaint_data = NULL;
2678}
2679
2680/**
2681 * Cancel a repaint set
2682 *
2683 * Called by the core compositor when a repaint has finished, so the data
2684 * held across the repaint cycle should be discarded.
2685 */
2686static void
2687drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
2688{
2689 struct drm_backend *b = to_drm_backend(compositor);
2690 struct drm_pending_state *pending_state = repaint_data;
2691
2692 drm_pending_state_free(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002693 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002694 b->repaint_data = NULL;
2695}
2696
Daniel Stone598ee9d2016-11-16 11:55:20 +00002697#ifdef HAVE_DRM_ATOMIC
2698static void
2699atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
2700 unsigned int usec, unsigned int crtc_id, void *data)
2701{
2702 struct drm_backend *b = data;
2703 struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
2704 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2705 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2706 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
2707
2708 /* During the initial modeset, we can disable CRTCs which we don't
2709 * actually handle during normal operation; this will give us events
2710 * for unknown outputs. Ignore them. */
2711 if (!output || !output->base.enabled)
2712 return;
2713
2714 drm_output_update_msc(output, frame);
2715
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03002716 drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002717 assert(b->atomic_modeset);
2718 assert(output->atomic_complete_pending);
2719 output->atomic_complete_pending = 0;
2720
2721 drm_output_update_complete(output, flags, sec, usec);
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03002722 drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002723}
2724#endif
2725
Daniel Stonef8290622016-12-09 17:32:10 +00002726static struct drm_plane_state *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002727drm_output_prepare_overlay_view(struct drm_output_state *output_state,
Daniel Stonea284d272018-07-10 18:40:12 +01002728 struct weston_view *ev,
2729 enum drm_output_propose_state_mode mode)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002730{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002731 struct drm_output *output = output_state->output;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002732 struct weston_compositor *ec = output->base.compositor;
Daniel Stoned6e2a762016-11-16 19:33:20 +00002733 struct drm_backend *b = to_drm_backend(ec);
Daniel Stone08d4edf2017-04-04 17:54:34 +01002734 struct drm_plane *p;
Daniel Stonebc15f682016-11-14 16:57:01 +00002735 struct drm_plane_state *state = NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00002736 struct drm_fb *fb;
Daniel Stonedb10df12016-12-08 13:15:58 +00002737 unsigned int i;
Daniel Stonea284d272018-07-10 18:40:12 +01002738 int ret;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002739 enum {
2740 NO_PLANES,
2741 NO_PLANES_WITH_FORMAT,
2742 NO_PLANES_ACCEPTED,
2743 PLACED_ON_PLANE,
2744 } availability = NO_PLANES;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002745
Daniel Stone44abfaa2018-07-10 14:31:06 +01002746 assert(!b->sprites_are_broken);
Daniel Stone87fab1c2019-06-17 11:13:20 +01002747 assert(b->atomic_modeset);
Kristian Høgsberg65bec242012-03-05 19:57:35 -05002748
Daniel Stonef11ec022016-11-17 17:32:42 +00002749 fb = drm_fb_get_from_view(output_state, ev);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002750 if (!fb) {
2751 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
2752 " couldn't get fb\n", ev);
Daniel Stone296d7a92016-10-21 18:05:37 +01002753 return NULL;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002754 }
Daniel Stone296d7a92016-10-21 18:05:37 +01002755
Daniel Stone085d2b92015-05-21 00:00:57 +01002756 wl_list_for_each(p, &b->plane_list, link) {
2757 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2758 continue;
2759
Daniel Stone5ff289a2017-10-07 12:59:02 +01002760 if (!drm_plane_is_available(p, output))
Daniel Stonebc15f682016-11-14 16:57:01 +00002761 continue;
2762
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002763 state = drm_output_state_get_plane(output_state, p);
2764 if (state->fb) {
2765 state = NULL;
2766 continue;
2767 }
2768
2769 if (availability == NO_PLANES)
2770 availability = NO_PLANES_WITH_FORMAT;
2771
Daniel Stonef11ec022016-11-17 17:32:42 +00002772 /* Check whether the format is supported */
2773 for (i = 0; i < p->count_formats; i++) {
Sergi Granellf4456222017-01-12 17:17:32 +00002774 unsigned int j;
2775
2776 if (p->formats[i].format != fb->format->format)
2777 continue;
2778
2779 if (fb->modifier == DRM_FORMAT_MOD_INVALID)
2780 break;
2781
2782 for (j = 0; j < p->formats[i].count_modifiers; j++) {
2783 if (p->formats[i].modifiers[j] == fb->modifier)
2784 break;
2785 }
2786 if (j != p->formats[i].count_modifiers)
Daniel Stonef11ec022016-11-17 17:32:42 +00002787 break;
2788 }
Philipp Zabel619958e2019-01-22 11:28:46 +01002789 if (i == p->count_formats) {
2790 drm_plane_state_put_back(state);
2791 state = NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00002792 continue;
Philipp Zabel619958e2019-01-22 11:28:46 +01002793 }
Daniel Stonef11ec022016-11-17 17:32:42 +00002794
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002795 if (availability == NO_PLANES_WITH_FORMAT)
2796 availability = NO_PLANES_ACCEPTED;
Daniel Stonebc15f682016-11-14 16:57:01 +00002797
Daniel Stonea284d272018-07-10 18:40:12 +01002798 state->ev = ev;
2799 state->output = output;
2800 if (!drm_plane_state_coords_for_view(state, ev)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002801 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
2802 "unsuitable transform\n", ev);
Daniel Stonea284d272018-07-10 18:40:12 +01002803 drm_plane_state_put_back(state);
2804 state = NULL;
2805 continue;
2806 }
Daniel Stonea284d272018-07-10 18:40:12 +01002807
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002808 /* If the surface buffer has an in-fence fd, but the plane
2809 * doesn't support fences, we can't place the buffer on this
2810 * plane. */
2811 if (ev->surface->acquire_fence_fd >= 0 &&
Daniel Stone87fab1c2019-06-17 11:13:20 +01002812 p->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002813 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
2814 "no in-fence support\n", ev);
2815 drm_plane_state_put_back(state);
2816 state = NULL;
2817 continue;
2818 }
2819
Daniel Stonea284d272018-07-10 18:40:12 +01002820 /* We hold one reference for the lifetime of this function;
2821 * from calling drm_fb_get_from_view, to the out label where
2822 * we unconditionally drop the reference. So, we take another
2823 * reference here to live within the state. */
2824 state->fb = drm_fb_ref(fb);
2825
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002826 state->in_fence_fd = ev->surface->acquire_fence_fd;
2827
Daniel Stonea284d272018-07-10 18:40:12 +01002828 /* In planes-only mode, we don't have an incremental state to
2829 * test against, so we just hope it'll work. */
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002830 if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
2831 drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
2832 "view %p on overlay %lu in planes-only mode\n",
2833 ev, (unsigned long) p->plane_id);
2834 availability = PLACED_ON_PLANE;
Daniel Stonea284d272018-07-10 18:40:12 +01002835 goto out;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002836 }
Daniel Stonea284d272018-07-10 18:40:12 +01002837
2838 ret = drm_pending_state_test(output_state->pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002839 if (ret == 0) {
2840 drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
2841 "view %p on overlay %d in mixed mode\n",
2842 ev, p->plane_id);
2843 availability = PLACED_ON_PLANE;
Daniel Stonea284d272018-07-10 18:40:12 +01002844 goto out;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002845 }
2846
2847 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay %lu "
2848 "in mixed mode: kernel test failed\n",
2849 ev, (unsigned long) p->plane_id);
Daniel Stonea284d272018-07-10 18:40:12 +01002850
2851 drm_plane_state_put_back(state);
2852 state = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002853 }
2854
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002855 switch (availability) {
2856 case NO_PLANES:
2857 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
2858 "no free overlay planes\n", ev);
2859 break;
2860 case NO_PLANES_WITH_FORMAT:
2861 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
Marius Vladd4c7bc52019-02-16 21:19:51 +02002862 "no free overlay planes matching format %s (0x%lx) "
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002863 "modifier 0x%llx\n",
Marius Vladd4c7bc52019-02-16 21:19:51 +02002864 ev, fb->format->drm_format_name,
2865 (unsigned long) fb->format,
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002866 (unsigned long long) fb->modifier);
2867 break;
2868 case NO_PLANES_ACCEPTED:
2869 case PLACED_ON_PLANE:
2870 break;
2871 }
2872
Daniel Stonea284d272018-07-10 18:40:12 +01002873out:
2874 drm_fb_unref(fb);
Daniel Stonef8290622016-12-09 17:32:10 +00002875 return state;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002876}
2877
Pekka Paalanend0ead482014-06-16 12:05:40 +03002878/**
2879 * Update the image for the current cursor surface
2880 *
Daniel Stone9b560382016-11-16 19:46:35 +00002881 * @param plane_state DRM cursor plane state
2882 * @param ev Source view for cursor
Pekka Paalanend0ead482014-06-16 12:05:40 +03002883 */
2884static void
Daniel Stone9b560382016-11-16 19:46:35 +00002885cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
Pekka Paalanend0ead482014-06-16 12:05:40 +03002886{
Daniel Stone9b560382016-11-16 19:46:35 +00002887 struct drm_backend *b = plane_state->plane->backend;
2888 struct gbm_bo *bo = plane_state->fb->bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03002889 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
2890 uint32_t buf[b->cursor_width * b->cursor_height];
2891 int32_t stride;
2892 uint8_t *s;
2893 int i;
2894
2895 assert(buffer && buffer->shm_buffer);
2896 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
Daniel Stone9b560382016-11-16 19:46:35 +00002897 assert(buffer->width <= b->cursor_width);
2898 assert(buffer->height <= b->cursor_height);
Pekka Paalanend0ead482014-06-16 12:05:40 +03002899
2900 memset(buf, 0, sizeof buf);
2901 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
2902 s = wl_shm_buffer_get_data(buffer->shm_buffer);
2903
2904 wl_shm_buffer_begin_access(buffer->shm_buffer);
Daniel Stone9b560382016-11-16 19:46:35 +00002905 for (i = 0; i < buffer->height; i++)
Pekka Paalanend0ead482014-06-16 12:05:40 +03002906 memcpy(buf + i * b->cursor_width,
2907 s + i * stride,
Daniel Stone9b560382016-11-16 19:46:35 +00002908 buffer->width * 4);
Pekka Paalanend0ead482014-06-16 12:05:40 +03002909 wl_shm_buffer_end_access(buffer->shm_buffer);
2910
2911 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Antonio Borneo39578632019-04-26 23:57:31 +02002912 weston_log("failed update cursor: %s\n", strerror(errno));
Pekka Paalanend0ead482014-06-16 12:05:40 +03002913}
2914
Daniel Stonef8290622016-12-09 17:32:10 +00002915static struct drm_plane_state *
Daniel Stone2ba17f42015-05-19 20:02:41 +01002916drm_output_prepare_cursor_view(struct drm_output_state *output_state,
2917 struct weston_view *ev)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002918{
Daniel Stone2ba17f42015-05-19 20:02:41 +01002919 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02002920 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone2ba17f42015-05-19 20:02:41 +01002921 struct drm_plane *plane = output->cursor_plane;
2922 struct drm_plane_state *plane_state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002923 struct wl_shm_buffer *shmbuf;
2924 bool needs_update = false;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05002925
Daniel Stonef7a2f832016-12-08 17:19:09 +00002926 assert(!b->cursors_are_broken);
Daniel Stone2ba17f42015-05-19 20:02:41 +01002927
Daniel Stonef7a2f832016-12-08 17:19:09 +00002928 if (!plane)
Daniel Stone2ba17f42015-05-19 20:02:41 +01002929 return NULL;
2930
2931 if (!plane->state_cur->complete)
2932 return NULL;
2933
2934 if (plane->state_cur->output && plane->state_cur->output != output)
2935 return NULL;
2936
Daniel Stone2ba17f42015-05-19 20:02:41 +01002937 /* We use GBM to import SHM buffers. */
2938 if (b->gbm == NULL)
2939 return NULL;
2940
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002941 if (ev->surface->buffer_ref.buffer == NULL) {
2942 drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
2943 "(no buffer available)\n", ev);
Daniel Stone2ba17f42015-05-19 20:02:41 +01002944 return NULL;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002945 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01002946 shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002947 if (!shmbuf) {
2948 drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
2949 "(buffer isn't SHM)\n", ev);
Daniel Stone2ba17f42015-05-19 20:02:41 +01002950 return NULL;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002951 }
2952 if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888) {
2953 drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
2954 "(format 0x%lx unsuitable)\n",
2955 ev, (unsigned long) wl_shm_buffer_get_format(shmbuf));
Daniel Stone2ba17f42015-05-19 20:02:41 +01002956 return NULL;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002957 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01002958
Daniel Stone2ba17f42015-05-19 20:02:41 +01002959 plane_state =
2960 drm_output_state_get_plane(output_state, output->cursor_plane);
2961
2962 if (plane_state && plane_state->fb)
2963 return NULL;
2964
Daniel Stone9b560382016-11-16 19:46:35 +00002965 /* We can't scale with the legacy API, and we don't try to account for
2966 * simple cropping/translation in cursor_bo_update. */
2967 plane_state->output = output;
2968 if (!drm_plane_state_coords_for_view(plane_state, ev))
2969 goto err;
2970
2971 if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
2972 plane_state->src_w > (unsigned) b->cursor_width << 16 ||
2973 plane_state->src_h > (unsigned) b->cursor_height << 16 ||
2974 plane_state->src_w != plane_state->dest_w << 16 ||
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002975 plane_state->src_h != plane_state->dest_h << 16) {
2976 drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
2977 "(positioning requires cropping or scaling)\n", ev);
Daniel Stone9b560382016-11-16 19:46:35 +00002978 goto err;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002979 }
Daniel Stone9b560382016-11-16 19:46:35 +00002980
Daniel Stone2ba17f42015-05-19 20:02:41 +01002981 /* Since we're setting plane state up front, we need to work out
2982 * whether or not we need to upload a new cursor. We can't use the
2983 * plane damage, since the planes haven't actually been calculated
2984 * yet: instead try to figure it out directly. KMS cursor planes are
2985 * pretty unique here, in that they lie partway between a Weston plane
2986 * (direct scanout) and a renderer. */
2987 if (ev != output->cursor_view ||
2988 pixman_region32_not_empty(&ev->surface->damage)) {
2989 output->current_cursor++;
2990 output->current_cursor =
2991 output->current_cursor %
2992 ARRAY_LENGTH(output->gbm_cursor_fb);
2993 needs_update = true;
2994 }
2995
2996 output->cursor_view = ev;
Daniel Stoneee1aea72017-12-18 13:41:09 +00002997 plane_state->ev = ev;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002998
2999 plane_state->fb =
3000 drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
Daniel Stone9b560382016-11-16 19:46:35 +00003001
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003002 if (needs_update) {
3003 drm_debug(b, "\t\t\t\t[cursor] copying new content to cursor BO\n");
Daniel Stone9b560382016-11-16 19:46:35 +00003004 cursor_bo_update(plane_state, ev);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003005 }
Daniel Stone9b560382016-11-16 19:46:35 +00003006
3007 /* The cursor API is somewhat special: in cursor_bo_update(), we upload
3008 * a buffer which is always cursor_width x cursor_height, even if the
3009 * surface we want to promote is actually smaller than this. Manually
3010 * mangle the plane state to deal with this. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01003011 plane_state->src_w = b->cursor_width << 16;
3012 plane_state->src_h = b->cursor_height << 16;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003013 plane_state->dest_w = b->cursor_width;
3014 plane_state->dest_h = b->cursor_height;
3015
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003016 drm_debug(b, "\t\t\t\t[cursor] provisionally assigned view %p to cursor\n",
3017 ev);
3018
Daniel Stonef8290622016-12-09 17:32:10 +00003019 return plane_state;
Daniel Stone9b560382016-11-16 19:46:35 +00003020
3021err:
3022 drm_plane_state_put_back(plane_state);
3023 return NULL;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003024}
3025
3026static void
3027drm_output_set_cursor(struct drm_output_state *output_state)
3028{
3029 struct drm_output *output = output_state->output;
3030 struct drm_backend *b = to_drm_backend(output->base.compositor);
3031 struct drm_plane *plane = output->cursor_plane;
3032 struct drm_plane_state *state;
3033 EGLint handle;
3034 struct gbm_bo *bo;
3035
3036 if (!plane)
3037 return;
3038
3039 state = drm_output_state_get_existing_plane(output_state, plane);
3040 if (!state)
3041 return;
3042
3043 if (!state->fb) {
3044 pixman_region32_fini(&plane->base.damage);
3045 pixman_region32_init(&plane->base.damage);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003046 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003047 return;
3048 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003049
Daniel Stone2ba17f42015-05-19 20:02:41 +01003050 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
3051 assert(!plane->state_cur->output || plane->state_cur->output == output);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003052
Daniel Stone2ba17f42015-05-19 20:02:41 +01003053 if (plane->state_cur->fb != state->fb) {
3054 bo = state->fb->bo;
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04003055 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03003056 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
Daniel Stone2ba17f42015-05-19 20:02:41 +01003057 b->cursor_width, b->cursor_height)) {
Antonio Borneo39578632019-04-26 23:57:31 +02003058 weston_log("failed to set cursor: %s\n",
3059 strerror(errno));
Daniel Stone2ba17f42015-05-19 20:02:41 +01003060 goto err;
Rob Clarkab5b1e32012-08-09 13:24:45 -05003061 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003062 }
3063
Daniel Stone2ba17f42015-05-19 20:02:41 +01003064 pixman_region32_fini(&plane->base.damage);
3065 pixman_region32_init(&plane->base.damage);
Pekka Paalanen7eaed402015-11-27 14:20:58 +02003066
Daniel Stone2ba17f42015-05-19 20:02:41 +01003067 if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
3068 state->dest_x, state->dest_y)) {
Antonio Borneo39578632019-04-26 23:57:31 +02003069 weston_log("failed to move cursor: %s\n", strerror(errno));
Daniel Stone2ba17f42015-05-19 20:02:41 +01003070 goto err;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003071 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003072
3073 return;
3074
3075err:
3076 b->cursors_are_broken = 1;
3077 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003078}
3079
Daniel Stoneee1aea72017-12-18 13:41:09 +00003080static struct drm_output_state *
3081drm_output_propose_state(struct weston_output *output_base,
Daniel Stonef7a2f832016-12-08 17:19:09 +00003082 struct drm_pending_state *pending_state,
3083 enum drm_output_propose_state_mode mode)
Daniel Stoneee1aea72017-12-18 13:41:09 +00003084{
3085 struct drm_output *output = to_drm_output(output_base);
Daniel Stone44abfaa2018-07-10 14:31:06 +01003086 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003087 struct drm_output_state *state;
Daniel Stonea284d272018-07-10 18:40:12 +01003088 struct drm_plane_state *scanout_state = NULL;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003089 struct weston_view *ev;
Daniel Stone81082392016-12-09 18:03:31 +00003090 pixman_region32_t surface_overlap, renderer_region, occluded_region;
Daniel Stonef7a2f832016-12-08 17:19:09 +00003091 bool planes_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY);
Daniel Stoned12e5162018-07-10 18:19:37 +01003092 bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003093 int ret;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003094
3095 assert(!output->state_last);
3096 state = drm_output_state_duplicate(output->state_cur,
3097 pending_state,
3098 DRM_OUTPUT_STATE_CLEAR_PLANES);
3099
Daniel Stonea284d272018-07-10 18:40:12 +01003100 /* We implement mixed mode by progressively creating and testing
3101 * incremental states, of scanout + overlay + cursor. Since we
3102 * walk our views top to bottom, the scanout plane is last, however
3103 * we always need it in our scene for the test modeset to be
3104 * meaningful. To do this, we steal a reference to the last
3105 * renderer framebuffer we have, if we think it's basically
3106 * compatible. If we don't have that, then we conservatively fall
3107 * back to only using the renderer for this repaint. */
3108 if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
3109 struct drm_plane *plane = output->scanout_plane;
3110 struct drm_fb *scanout_fb = plane->state_cur->fb;
3111
3112 if (!scanout_fb ||
3113 (scanout_fb->type != BUFFER_GBM_SURFACE &&
3114 scanout_fb->type != BUFFER_PIXMAN_DUMB)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003115 drm_debug(b, "\t\t[state] cannot propose mixed mode: "
3116 "for output %s (%lu): no previous renderer "
3117 "fb\n",
3118 output->base.name,
3119 (unsigned long) output->base.id);
Daniel Stonea284d272018-07-10 18:40:12 +01003120 drm_output_state_free(state);
3121 return NULL;
3122 }
3123
3124 if (scanout_fb->width != output_base->current_mode->width ||
3125 scanout_fb->height != output_base->current_mode->height) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003126 drm_debug(b, "\t\t[state] cannot propose mixed mode "
3127 "for output %s (%lu): previous fb has "
3128 "different size\n",
3129 output->base.name,
3130 (unsigned long) output->base.id);
Daniel Stonea284d272018-07-10 18:40:12 +01003131 drm_output_state_free(state);
3132 return NULL;
3133 }
3134
3135 scanout_state = drm_plane_state_duplicate(state,
3136 plane->state_cur);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003137 drm_debug(b, "\t\t[state] using renderer FB ID %lu for mixed "
3138 "mode for output %s (%lu)\n",
3139 (unsigned long) scanout_fb->fb_id, output->base.name,
3140 (unsigned long) output->base.id);
Daniel Stonea284d272018-07-10 18:40:12 +01003141 }
3142
Daniel Stoneee1aea72017-12-18 13:41:09 +00003143 /*
3144 * Find a surface for each sprite in the output using some heuristics:
3145 * 1) size
3146 * 2) frequency of update
3147 * 3) opacity (though some hw might support alpha blending)
3148 * 4) clipping (this can be fixed with color keys)
3149 *
3150 * The idea is to save on blitting since this should save power.
3151 * If we can get a large video surface on the sprite for example,
3152 * the main display surface may not need to update at all, and
3153 * the client buffer can be used directly for the sprite surface
3154 * as we do for flipping full screen surfaces.
3155 */
3156 pixman_region32_init(&renderer_region);
Daniel Stone81082392016-12-09 18:03:31 +00003157 pixman_region32_init(&occluded_region);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003158
3159 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
Daniel Stonef8290622016-12-09 17:32:10 +00003160 struct drm_plane_state *ps = NULL;
3161 bool force_renderer = false;
Daniel Stone81082392016-12-09 18:03:31 +00003162 pixman_region32_t clipped_view;
Daniel Stoneb41abf92018-07-11 13:03:31 +01003163 bool totally_occluded = false;
3164 bool overlay_occluded = false;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003165
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003166 drm_debug(b, "\t\t\t[view] evaluating view %p for "
3167 "output %s (%lu)\n",
3168 ev, output->base.name,
3169 (unsigned long) output->base.id);
3170
Daniel Stone231ae2f2016-11-29 21:03:44 +00003171 /* If this view doesn't touch our output at all, there's no
3172 * reason to do anything with it. */
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003173 if (!(ev->output_mask & (1u << output->base.id))) {
3174 drm_debug(b, "\t\t\t\t[view] ignoring view %p "
3175 "(not on our output)\n", ev);
Daniel Stone231ae2f2016-11-29 21:03:44 +00003176 continue;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003177 }
Daniel Stone231ae2f2016-11-29 21:03:44 +00003178
3179 /* We only assign planes to views which are exclusively present
3180 * on our output. */
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003181 if (ev->output_mask != (1u << output->base.id)) {
3182 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3183 "(on multiple outputs)\n", ev);
Daniel Stonef8290622016-12-09 17:32:10 +00003184 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003185 }
Daniel Stone231ae2f2016-11-29 21:03:44 +00003186
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003187 if (!ev->surface->buffer_ref.buffer) {
3188 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3189 "(no buffer available)\n", ev);
Daniel Stoneca6fbe32018-07-10 18:08:12 +01003190 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003191 }
Daniel Stoneca6fbe32018-07-10 18:08:12 +01003192
Daniel Stone81082392016-12-09 18:03:31 +00003193 /* Ignore views we know to be totally occluded. */
3194 pixman_region32_init(&clipped_view);
3195 pixman_region32_intersect(&clipped_view,
3196 &ev->transform.boundingbox,
3197 &output->base.region);
3198
3199 pixman_region32_init(&surface_overlap);
3200 pixman_region32_subtract(&surface_overlap, &clipped_view,
3201 &occluded_region);
Daniel Stoneb41abf92018-07-11 13:03:31 +01003202 totally_occluded = !pixman_region32_not_empty(&surface_overlap);
3203 if (totally_occluded) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003204 drm_debug(b, "\t\t\t\t[view] ignoring view %p "
3205 "(occluded on our output)\n", ev);
Daniel Stone81082392016-12-09 18:03:31 +00003206 pixman_region32_fini(&surface_overlap);
3207 pixman_region32_fini(&clipped_view);
3208 continue;
3209 }
3210
Daniel Stoneee1aea72017-12-18 13:41:09 +00003211 /* Since we process views from top to bottom, we know that if
3212 * the view intersects the calculated renderer region, it must
3213 * be part of, or occluded by, it, and cannot go on a plane. */
Daniel Stoneee1aea72017-12-18 13:41:09 +00003214 pixman_region32_intersect(&surface_overlap, &renderer_region,
Daniel Stone81082392016-12-09 18:03:31 +00003215 &clipped_view);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003216 if (pixman_region32_not_empty(&surface_overlap)) {
3217 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3218 "(occluded by renderer views)\n", ev);
Daniel Stonef8290622016-12-09 17:32:10 +00003219 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003220 }
Daniel Stonea0f82762018-07-10 11:44:25 +01003221
3222 /* We do not control the stacking order of overlay planes;
3223 * the scanout plane is strictly stacked bottom and the cursor
3224 * plane top, but the ordering of overlay planes with respect
3225 * to each other is undefined. Make sure we do not have two
3226 * planes overlapping each other. */
3227 pixman_region32_intersect(&surface_overlap, &occluded_region,
3228 &clipped_view);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003229 if (pixman_region32_not_empty(&surface_overlap)) {
3230 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3231 "(occluded by other overlay planes)\n", ev);
Daniel Stoneb41abf92018-07-11 13:03:31 +01003232 overlay_occluded = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003233 }
Daniel Stoneee1aea72017-12-18 13:41:09 +00003234 pixman_region32_fini(&surface_overlap);
3235
Daniel Stonef7a2f832016-12-08 17:19:09 +00003236 /* The cursor plane is 'special' in the sense that we can still
3237 * place it in the legacy API, and we gate that with a separate
3238 * cursors_are_broken flag. */
Daniel Stoneb41abf92018-07-11 13:03:31 +01003239 if (!force_renderer && !overlay_occluded && !b->cursors_are_broken)
Daniel Stonef8290622016-12-09 17:32:10 +00003240 ps = drm_output_prepare_cursor_view(state, ev);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003241
Daniel Stonef8290622016-12-09 17:32:10 +00003242 /* If sprites are disabled or the view is not fully opaque, we
3243 * must put the view into the renderer - unless it has already
3244 * been placed in the cursor plane, which can handle alpha. */
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003245 if (!ps && !planes_ok) {
3246 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3247 "(precluded by mode)\n", ev);
Daniel Stonef8290622016-12-09 17:32:10 +00003248 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003249 }
Philipp Zabelfff27972018-09-03 20:13:52 +02003250 if (!ps && !weston_view_is_opaque(ev, &clipped_view)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003251 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3252 "(view not fully opaque)\n", ev);
Daniel Stonef8290622016-12-09 17:32:10 +00003253 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003254 }
Daniel Stone81082392016-12-09 18:03:31 +00003255
Daniel Stonea284d272018-07-10 18:40:12 +01003256 /* Only try to place scanout surfaces in planes-only mode; in
3257 * mixed mode, we have already failed to place a view on the
3258 * scanout surface, forcing usage of the renderer on the
3259 * scanout plane. */
3260 if (!ps && !force_renderer && !renderer_ok)
3261 ps = drm_output_prepare_scanout_view(state, ev, mode);
Daniel Stoneb41abf92018-07-11 13:03:31 +01003262
3263 if (!ps && !overlay_occluded && !force_renderer)
Daniel Stonea284d272018-07-10 18:40:12 +01003264 ps = drm_output_prepare_overlay_view(state, ev, mode);
Daniel Stone44abfaa2018-07-10 14:31:06 +01003265
Daniel Stonef8290622016-12-09 17:32:10 +00003266 if (ps) {
Daniel Stonef7a2f832016-12-08 17:19:09 +00003267 /* If we have been assigned to an overlay or scanout
3268 * plane, add this area to the occluded region, so
3269 * other views are known to be behind it. The cursor
3270 * plane, however, is special, in that it blends with
3271 * the content underneath it: the area should neither
3272 * be added to the renderer region nor the occluded
3273 * region. */
Daniel Stonef8290622016-12-09 17:32:10 +00003274 if (ps->plane->type != WDRM_PLANE_TYPE_CURSOR) {
Daniel Stonef7a2f832016-12-08 17:19:09 +00003275 pixman_region32_union(&occluded_region,
3276 &occluded_region,
3277 &clipped_view);
3278 pixman_region32_fini(&clipped_view);
3279 }
3280 continue;
3281 }
Daniel Stoneee1aea72017-12-18 13:41:09 +00003282
Daniel Stoned12e5162018-07-10 18:19:37 +01003283 /* We have been assigned to the primary (renderer) plane:
3284 * check if this is OK, and add ourselves to the renderer
3285 * region if so. */
3286 if (!renderer_ok) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003287 drm_debug(b, "\t\t[view] failing state generation: "
3288 "placing view %p to renderer not allowed\n",
3289 ev);
Daniel Stoned12e5162018-07-10 18:19:37 +01003290 pixman_region32_fini(&clipped_view);
3291 goto err_region;
3292 }
3293
Daniel Stonef7a2f832016-12-08 17:19:09 +00003294 pixman_region32_union(&renderer_region,
3295 &renderer_region,
3296 &clipped_view);
Daniel Stone81082392016-12-09 18:03:31 +00003297 pixman_region32_fini(&clipped_view);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003298 }
3299 pixman_region32_fini(&renderer_region);
Daniel Stone81082392016-12-09 18:03:31 +00003300 pixman_region32_fini(&occluded_region);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003301
Daniel Stone11789222018-07-20 19:55:37 +01003302 /* In renderer-only mode, we can't test the state as we don't have a
3303 * renderer buffer yet. */
3304 if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY)
3305 return state;
3306
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003307 /* Check to see if this state will actually work. */
3308 ret = drm_pending_state_test(state->pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003309 if (ret != 0) {
3310 drm_debug(b, "\t\t[view] failing state generation: "
3311 "atomic test not OK\n");
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003312 goto err;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003313 }
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003314
Daniel Stonea284d272018-07-10 18:40:12 +01003315 /* Counterpart to duplicating scanout state at the top of this
3316 * function: if we have taken a renderer framebuffer and placed it in
3317 * the pending state in order to incrementally test overlay planes,
3318 * remove it now. */
3319 if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
3320 assert(scanout_state->fb->type == BUFFER_GBM_SURFACE ||
3321 scanout_state->fb->type == BUFFER_PIXMAN_DUMB);
3322 drm_plane_state_put_back(scanout_state);
3323 }
Daniel Stoneee1aea72017-12-18 13:41:09 +00003324 return state;
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003325
Daniel Stoned12e5162018-07-10 18:19:37 +01003326err_region:
3327 pixman_region32_fini(&renderer_region);
3328 pixman_region32_fini(&occluded_region);
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003329err:
3330 drm_output_state_free(state);
3331 return NULL;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003332}
3333
Marius Vlad5d767412018-12-14 11:56:10 +02003334static const char *
3335drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
3336{
3337 if (mode < 0 || mode >= ARRAY_LENGTH(drm_output_propose_state_mode_as_string))
3338 return " unknown compositing mode";
3339
3340 return drm_output_propose_state_mode_as_string[mode];
3341}
3342
Daniel Stoneee1aea72017-12-18 13:41:09 +00003343static void
3344drm_assign_planes(struct weston_output *output_base, void *repaint_data)
3345{
3346 struct drm_backend *b = to_drm_backend(output_base->compositor);
3347 struct drm_pending_state *pending_state = repaint_data;
3348 struct drm_output *output = to_drm_output(output_base);
Daniel Stonef7a2f832016-12-08 17:19:09 +00003349 struct drm_output_state *state = NULL;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003350 struct drm_plane_state *plane_state;
3351 struct weston_view *ev;
3352 struct weston_plane *primary = &output_base->compositor->primary_plane;
Marius Vlad5d767412018-12-14 11:56:10 +02003353 enum drm_output_propose_state_mode mode = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003354
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003355 drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
3356 output_base->name, (unsigned long) output_base->id);
3357
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003358 if (!b->sprites_are_broken && !output->virtual) {
Marius Vlad5d767412018-12-14 11:56:10 +02003359 drm_debug(b, "\t[repaint] trying planes-only build state\n");
3360 state = drm_output_propose_state(output_base, pending_state, mode);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003361 if (!state) {
3362 drm_debug(b, "\t[repaint] could not build planes-only "
3363 "state, trying mixed\n");
Marius Vlad5d767412018-12-14 11:56:10 +02003364 mode = DRM_OUTPUT_PROPOSE_STATE_MIXED;
3365 state = drm_output_propose_state(output_base,
3366 pending_state,
3367 mode);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003368 }
3369 if (!state) {
3370 drm_debug(b, "\t[repaint] could not build mixed-mode "
3371 "state, trying renderer-only\n");
3372 }
3373 } else {
3374 drm_debug(b, "\t[state] no overlay plane support\n");
Daniel Stoned12e5162018-07-10 18:19:37 +01003375 }
Daniel Stonef7a2f832016-12-08 17:19:09 +00003376
Marius Vlad5d767412018-12-14 11:56:10 +02003377 if (!state) {
3378 mode = DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY;
Daniel Stonef7a2f832016-12-08 17:19:09 +00003379 state = drm_output_propose_state(output_base, pending_state,
Marius Vladc91cf302018-12-21 12:48:22 +02003380 mode);
Marius Vlad5d767412018-12-14 11:56:10 +02003381 }
Daniel Stonef7a2f832016-12-08 17:19:09 +00003382
3383 assert(state);
Marius Vlad5d767412018-12-14 11:56:10 +02003384 drm_debug(b, "\t[repaint] Using %s composition\n",
3385 drm_propose_state_mode_to_string(mode));
Daniel Stoneee1aea72017-12-18 13:41:09 +00003386
3387 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
3388 struct drm_plane *target_plane = NULL;
3389
Daniel Stone231ae2f2016-11-29 21:03:44 +00003390 /* If this view doesn't touch our output at all, there's no
3391 * reason to do anything with it. */
3392 if (!(ev->output_mask & (1u << output->base.id)))
3393 continue;
3394
Daniel Stoneee1aea72017-12-18 13:41:09 +00003395 /* Test whether this buffer can ever go into a plane:
3396 * non-shm, or small enough to be a cursor.
3397 *
3398 * Also, keep a reference when using the pixman renderer.
3399 * That makes it possible to do a seamless switch to the GL
3400 * renderer and since the pixman renderer keeps a reference
3401 * to the buffer anyway, there is no side effects.
3402 */
3403 if (b->use_pixman ||
3404 (ev->surface->buffer_ref.buffer &&
3405 (!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
3406 (ev->surface->width <= b->cursor_width &&
3407 ev->surface->height <= b->cursor_height))))
3408 ev->surface->keep_buffer = true;
3409 else
3410 ev->surface->keep_buffer = false;
3411
3412 /* This is a bit unpleasant, but lacking a temporary place to
3413 * hang a plane off the view, we have to do a nested walk.
3414 * Our first-order iteration has to be planes rather than
3415 * views, because otherwise we won't reset views which were
3416 * previously on planes to being on the primary plane. */
3417 wl_list_for_each(plane_state, &state->plane_list, link) {
3418 if (plane_state->ev == ev) {
3419 plane_state->ev = NULL;
3420 target_plane = plane_state->plane;
3421 break;
3422 }
3423 }
3424
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003425 if (target_plane) {
3426 drm_debug(b, "\t[repaint] view %p on %s plane %lu\n",
3427 ev, plane_type_enums[target_plane->type].name,
3428 (unsigned long) target_plane->plane_id);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003429 weston_view_move_to_plane(ev, &target_plane->base);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003430 } else {
3431 drm_debug(b, "\t[repaint] view %p using renderer "
3432 "composition\n", ev);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003433 weston_view_move_to_plane(ev, primary);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003434 }
Daniel Stoneee1aea72017-12-18 13:41:09 +00003435
3436 if (!target_plane ||
3437 target_plane->type == WDRM_PLANE_TYPE_CURSOR) {
3438 /* cursor plane & renderer involve a copy */
3439 ev->psf_flags = 0;
3440 } else {
3441 /* All other planes are a direct scanout of a
3442 * single client buffer.
3443 */
3444 ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
3445 }
3446 }
3447
3448 /* We rely on output->cursor_view being both an accurate reflection of
3449 * the cursor plane's state, but also being maintained across repaints
3450 * to avoid unnecessary damage uploads, per the comment in
3451 * drm_output_prepare_cursor_view. In the event that we go from having
3452 * a cursor view to not having a cursor view, we need to clear it. */
3453 if (output->cursor_view) {
3454 plane_state =
3455 drm_output_state_get_existing_plane(state,
3456 output->cursor_plane);
3457 if (!plane_state || !plane_state->fb)
3458 output->cursor_view = NULL;
3459 }
3460}
3461
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303462/*
3463 * Get the aspect-ratio from drmModeModeInfo mode flags.
3464 *
3465 * @param drm_mode_flags- flags from drmModeModeInfo structure.
3466 * @returns aspect-ratio as encoded in enum 'weston_mode_aspect_ratio'.
3467 */
3468static enum weston_mode_aspect_ratio
3469drm_to_weston_mode_aspect_ratio(uint32_t drm_mode_flags)
3470{
3471 return (drm_mode_flags & DRM_MODE_FLAG_PIC_AR_MASK) >>
3472 DRM_MODE_FLAG_PIC_AR_BITS_POS;
3473}
3474
3475static const char *
3476aspect_ratio_to_string(enum weston_mode_aspect_ratio ratio)
3477{
3478 if (ratio < 0 || ratio >= ARRAY_LENGTH(aspect_ratio_as_string) ||
3479 !aspect_ratio_as_string[ratio])
3480 return " (unknown aspect ratio)";
3481
3482 return aspect_ratio_as_string[ratio];
3483}
3484
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003485/**
3486 * Find the closest-matching mode for a given target
3487 *
3488 * Given a target mode, find the most suitable mode amongst the output's
3489 * current mode list to use, preferring the current mode if possible, to
3490 * avoid an expensive mode switch.
3491 *
3492 * @param output DRM output
3493 * @param target_mode Mode to attempt to match
3494 * @returns Pointer to a mode from the output's mode list
3495 */
Alex Wub7b8bda2012-04-17 17:20:48 +08003496static struct drm_mode *
3497choose_mode (struct drm_output *output, struct weston_mode *target_mode)
3498{
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303499 struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode;
3500 enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE;
3501 enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE;
3502 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08003503
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303504 b = to_drm_backend(output->base.compositor);
3505 target_aspect = target_mode->aspect_ratio;
3506 src_aspect = output->base.current_mode->aspect_ratio;
Hardeningff39efa2013-09-18 23:56:35 +02003507 if (output->base.current_mode->width == target_mode->width &&
3508 output->base.current_mode->height == target_mode->height &&
3509 (output->base.current_mode->refresh == target_mode->refresh ||
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303510 target_mode->refresh == 0)) {
3511 if (!b->aspect_ratio_supported || src_aspect == target_aspect)
3512 return to_drm_mode(output->base.current_mode);
3513 }
Alex Wub7b8bda2012-04-17 17:20:48 +08003514
3515 wl_list_for_each(mode, &output->base.mode_list, base.link) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303516
3517 src_aspect = mode->base.aspect_ratio;
Alex Wub7b8bda2012-04-17 17:20:48 +08003518 if (mode->mode_info.hdisplay == target_mode->width &&
3519 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02003520 if (mode->base.refresh == target_mode->refresh ||
3521 target_mode->refresh == 0) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303522 if (!b->aspect_ratio_supported ||
3523 src_aspect == target_aspect)
3524 return mode;
3525 else if (!mode_fall_back)
3526 mode_fall_back = mode;
3527 } else if (!tmp_mode) {
Alex Wub7b8bda2012-04-17 17:20:48 +08003528 tmp_mode = mode;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303529 }
Alex Wub7b8bda2012-04-17 17:20:48 +08003530 }
3531 }
3532
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303533 if (mode_fall_back)
3534 return mode_fall_back;
3535
Alex Wub7b8bda2012-04-17 17:20:48 +08003536 return tmp_mode;
3537}
3538
3539static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003540drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003541static void
3542drm_output_fini_egl(struct drm_output *output);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003543static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003544drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003545static void
3546drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003547
3548static int
Alex Wub7b8bda2012-04-17 17:20:48 +08003549drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
3550{
Daniel Stone02d487a2017-10-07 14:01:45 +01003551 struct drm_output *output = to_drm_output(output_base);
3552 struct drm_backend *b = to_drm_backend(output_base->compositor);
3553 struct drm_mode *drm_mode = choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +08003554
3555 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +01003556 weston_log("%s: invalid resolution %dx%d\n",
3557 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08003558 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003559 }
3560
Hardeningff39efa2013-09-18 23:56:35 +02003561 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08003562 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003563
Hardeningff39efa2013-09-18 23:56:35 +02003564 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003565
Hardeningff39efa2013-09-18 23:56:35 +02003566 output->base.current_mode = &drm_mode->base;
3567 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08003568 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
3569
Daniel Stonef30a18c2017-04-04 17:54:31 +01003570 /* XXX: This drops our current buffer too early, before we've started
3571 * displaying it. Ideally this should be much more atomic and
3572 * integrated with a full repaint cycle, rather than doing a
3573 * sledgehammer modeswitch first, and only later showing new
3574 * content.
3575 */
Daniel Stone6020f472018-02-05 15:46:20 +00003576 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +08003577
Giulio Camuffo954f1832014-10-11 18:27:30 +03003578 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003579 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003580 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003581 weston_log("failed to init output pixman state with "
3582 "new mode\n");
3583 return -1;
3584 }
3585 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +00003586 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003587 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003588 weston_log("failed to init output egl state with "
3589 "new mode");
3590 return -1;
3591 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003592 }
3593
Alex Wub7b8bda2012-04-17 17:20:48 +08003594 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003595}
3596
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003597static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003598on_drm_input(int fd, uint32_t mask, void *data)
3599{
Daniel Stone598ee9d2016-11-16 11:55:20 +00003600#ifdef HAVE_DRM_ATOMIC
3601 struct drm_backend *b = data;
3602#endif
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003603 drmEventContext evctx;
3604
3605 memset(&evctx, 0, sizeof evctx);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003606#ifndef HAVE_DRM_ATOMIC
Emil Velikov863e66b2017-04-04 18:07:34 +01003607 evctx.version = 2;
Daniel Stone598ee9d2016-11-16 11:55:20 +00003608#else
3609 evctx.version = 3;
3610 if (b->atomic_modeset)
3611 evctx.page_flip_handler2 = atomic_flip_handler;
3612 else
3613#endif
3614 evctx.page_flip_handler = page_flip_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003615 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003616
3617 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003618}
3619
3620static int
Daniel Stoneefa504f2016-12-19 16:48:20 +00003621init_kms_caps(struct drm_backend *b)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003622{
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003623 uint64_t cap;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003624 int ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003625 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003626
Daniel Stoneefa504f2016-12-19 16:48:20 +00003627 weston_log("using %s\n", b->drm.filename);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003628
Daniel Stoneefa504f2016-12-19 16:48:20 +00003629 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003630 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003631 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003632 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003633 clk_id = CLOCK_REALTIME;
3634
Giulio Camuffo954f1832014-10-11 18:27:30 +03003635 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003636 weston_log("Error: failed to set presentation clock %d.\n",
3637 clk_id);
3638 return -1;
3639 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02003640
Daniel Stoneefa504f2016-12-19 16:48:20 +00003641 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003642 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003643 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003644 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003645 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003646
Daniel Stoneefa504f2016-12-19 16:48:20 +00003647 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003648 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003649 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003650 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003651 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003652
Daniel Stonebe1090b2017-09-06 17:29:57 +01003653 if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
3654 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
3655 b->universal_planes = (ret == 0);
3656 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003657 weston_log("DRM: %s universal planes\n",
3658 b->universal_planes ? "supports" : "does not support");
3659
Pekka Paalanencd011a62016-11-15 22:07:49 +00003660#ifdef HAVE_DRM_ATOMIC
3661 if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00003662 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
3663 if (ret != 0)
3664 cap = 0;
Pekka Paalanencd011a62016-11-15 22:07:49 +00003665 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003666 b->atomic_modeset = ((ret == 0) && (cap == 1));
Pekka Paalanencd011a62016-11-15 22:07:49 +00003667 }
3668#endif
3669 weston_log("DRM: %s atomic modesetting\n",
3670 b->atomic_modeset ? "supports" : "does not support");
3671
Deepak Rawata864f582018-08-24 13:16:03 -07003672#ifdef HAVE_DRM_ADDFB2_MODIFIERS
3673 ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
3674 if (ret == 0)
3675 b->fb_modifiers = cap;
3676 else
3677#endif
3678 b->fb_modifiers = 0;
3679
Daniel Stone678aabe2016-12-09 16:00:12 +00003680 /*
3681 * KMS support for hardware planes cannot properly synchronize
3682 * without nuclear page flip. Without nuclear/atomic, hw plane
3683 * and cursor plane updates would either tear or cause extra
3684 * waits for vblanks which means dropping the compositor framerate
3685 * to a fraction. For cursors, it's not so bad, so they are
3686 * enabled.
3687 */
Marius Vladbe578572019-01-25 12:56:24 +02003688 if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
Daniel Stone678aabe2016-12-09 16:00:12 +00003689 b->sprites_are_broken = 1;
3690
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303691 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
3692 b->aspect_ratio_supported = (ret == 0);
3693 weston_log("DRM: %s picture aspect ratio\n",
3694 b->aspect_ratio_supported ? "supports" : "does not support");
3695
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003696 return 0;
3697}
3698
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003699static struct gbm_device *
3700create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003701{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003702 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01003703
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003704 gl_renderer = weston_load_module("gl-renderer.so",
3705 "gl_renderer_interface");
3706 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003707 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003708
3709 /* GBM will load a dri driver, but even though they need symbols from
3710 * libglapi, in some version of Mesa they are not linked to it. Since
3711 * only the gl-renderer module links to it, the call above won't make
3712 * these symbols globally available, and loading the DRI driver fails.
3713 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
3714 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
3715
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003716 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003717
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003718 return gbm;
3719}
3720
Bryce Harringtonc056a982015-05-19 15:25:18 -07003721/* When initializing EGL, if the preferred buffer format isn't available
Bryce Harringtonb9939982016-04-15 20:28:26 -07003722 * we may be able to substitute an ARGB format for an XRGB one.
Derek Foremanc4cfe852015-05-15 12:12:40 -05003723 *
3724 * This returns 0 if substitution isn't possible, but 0 might be a
3725 * legitimate format for other EGL platforms, so the caller is
3726 * responsible for checking for 0 before calling gl_renderer->create().
3727 *
3728 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
3729 * but it's entirely possible we'll see this again on other implementations.
3730 */
3731static int
3732fallback_format_for(uint32_t format)
3733{
3734 switch (format) {
3735 case GBM_FORMAT_XRGB8888:
3736 return GBM_FORMAT_ARGB8888;
3737 case GBM_FORMAT_XRGB2101010:
3738 return GBM_FORMAT_ARGB2101010;
3739 default:
3740 return 0;
3741 }
3742}
3743
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003744static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003745drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003746{
Derek Foreman6d556372015-11-04 14:47:33 -06003747 EGLint format[3] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003748 b->gbm_format,
3749 fallback_format_for(b->gbm_format),
Derek Foreman6d556372015-11-04 14:47:33 -06003750 0,
Derek Foremanc4cfe852015-05-15 12:12:40 -05003751 };
Derek Foreman6d556372015-11-04 14:47:33 -06003752 int n_formats = 2;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01003753
Derek Foremanc4cfe852015-05-15 12:12:40 -05003754 if (format[1])
Derek Foreman6d556372015-11-04 14:47:33 -06003755 n_formats = 3;
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003756 if (gl_renderer->display_create(b->compositor,
3757 EGL_PLATFORM_GBM_KHR,
3758 (void *)b->gbm,
Miguel A. Vico41700e32016-05-18 17:47:59 +02003759 NULL,
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003760 gl_renderer->opaque_attribs,
3761 format,
3762 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003763 return -1;
3764 }
3765
3766 return 0;
3767}
3768
3769static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003770init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003771{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003772 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003773
Giulio Camuffo954f1832014-10-11 18:27:30 +03003774 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003775 return -1;
3776
Giulio Camuffo954f1832014-10-11 18:27:30 +03003777 if (drm_backend_create_gl_renderer(b) < 0) {
3778 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003779 return -1;
3780 }
3781
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003782 return 0;
3783}
3784
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003785static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003786init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003787{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003788 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003789}
3790
Sergi Granellf4456222017-01-12 17:17:32 +00003791#ifdef HAVE_DRM_FORMATS_BLOB
3792static inline uint32_t *
3793formats_ptr(struct drm_format_modifier_blob *blob)
3794{
3795 return (uint32_t *)(((char *)blob) + blob->formats_offset);
3796}
3797
3798static inline struct drm_format_modifier *
3799modifiers_ptr(struct drm_format_modifier_blob *blob)
3800{
3801 return (struct drm_format_modifier *)
3802 (((char *)blob) + blob->modifiers_offset);
3803}
3804#endif
3805
3806/**
3807 * Populates the plane's formats array, using either the IN_FORMATS blob
3808 * property (if available), or the plane's format list if not.
3809 */
3810static int
3811drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
3812 const drmModeObjectProperties *props)
3813{
3814 unsigned i;
3815#ifdef HAVE_DRM_FORMATS_BLOB
3816 drmModePropertyBlobRes *blob;
3817 struct drm_format_modifier_blob *fmt_mod_blob;
3818 struct drm_format_modifier *blob_modifiers;
3819 uint32_t *blob_formats;
3820 uint32_t blob_id;
3821
3822 blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
3823 props,
3824 0);
3825 if (blob_id == 0)
3826 goto fallback;
3827
3828 blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
3829 if (!blob)
3830 goto fallback;
3831
3832 fmt_mod_blob = blob->data;
3833 blob_formats = formats_ptr(fmt_mod_blob);
3834 blob_modifiers = modifiers_ptr(fmt_mod_blob);
3835
3836 if (plane->count_formats != fmt_mod_blob->count_formats) {
3837 weston_log("DRM backend: format count differs between "
3838 "plane (%d) and IN_FORMATS (%d)\n",
3839 plane->count_formats,
3840 fmt_mod_blob->count_formats);
3841 weston_log("This represents a kernel bug; Weston is "
3842 "unable to continue.\n");
3843 abort();
3844 }
3845
3846 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
3847 uint32_t count_modifiers = 0;
3848 uint64_t *modifiers = NULL;
3849 unsigned j;
3850
3851 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
3852 struct drm_format_modifier *mod = &blob_modifiers[j];
3853
3854 if ((i < mod->offset) || (i > mod->offset + 63))
3855 continue;
3856 if (!(mod->formats & (1 << (i - mod->offset))))
3857 continue;
3858
3859 modifiers = realloc(modifiers,
3860 (count_modifiers + 1) *
3861 sizeof(modifiers[0]));
3862 assert(modifiers);
3863 modifiers[count_modifiers++] = mod->modifier;
3864 }
3865
3866 plane->formats[i].format = blob_formats[i];
3867 plane->formats[i].modifiers = modifiers;
3868 plane->formats[i].count_modifiers = count_modifiers;
3869 }
3870
3871 drmModeFreePropertyBlob(blob);
3872
3873 return 0;
3874
3875fallback:
3876#endif
3877 /* No IN_FORMATS blob available, so just use the old. */
3878 assert(plane->count_formats == kplane->count_formats);
3879 for (i = 0; i < kplane->count_formats; i++)
3880 plane->formats[i].format = kplane->formats[i];
3881
3882 return 0;
3883}
3884
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003885/**
Pekka Paalanenec272712014-06-05 11:22:25 +03003886 * Create a drm_plane for a hardware plane
3887 *
3888 * Creates one drm_plane structure for a hardware plane, and initialises its
3889 * properties and formats.
3890 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003891 * In the absence of universal plane support, where KMS does not explicitly
3892 * expose the primary and cursor planes to userspace, this may also create
3893 * an 'internal' plane for internal management.
3894 *
Pekka Paalanenec272712014-06-05 11:22:25 +03003895 * This function does not add the plane to the list of usable planes in Weston
3896 * itself; the caller is responsible for this.
3897 *
3898 * Call drm_plane_destroy to clean up the plane.
3899 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003900 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +03003901 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +01003902 * @param kplane DRM plane to create, or NULL if creating internal plane
3903 * @param output Output to create internal plane for, or NULL
3904 * @param type Type to use when creating internal plane, or invalid
3905 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +03003906 */
3907static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003908drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
3909 struct drm_output *output, enum wdrm_plane_type type,
3910 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +03003911{
3912 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003913 drmModeObjectProperties *props;
Sergi Granellf4456222017-01-12 17:17:32 +00003914 uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003915
Daniel Stone2ba17f42015-05-19 20:02:41 +01003916 plane = zalloc(sizeof(*plane) +
Sergi Granellf4456222017-01-12 17:17:32 +00003917 (sizeof(plane->formats[0]) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +03003918 if (!plane) {
3919 weston_log("%s: out of memory\n", __func__);
3920 return NULL;
3921 }
3922
3923 plane->backend = b;
Sergi Granellf4456222017-01-12 17:17:32 +00003924 plane->count_formats = num_formats;
Daniel Stonebc15f682016-11-14 16:57:01 +00003925 plane->state_cur = drm_plane_state_alloc(NULL, plane);
3926 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +03003927
Daniel Stone2ba17f42015-05-19 20:02:41 +01003928 if (kplane) {
3929 plane->possible_crtcs = kplane->possible_crtcs;
3930 plane->plane_id = kplane->plane_id;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003931
3932 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
3933 DRM_MODE_OBJECT_PLANE);
3934 if (!props) {
3935 weston_log("couldn't get plane properties\n");
3936 goto err;
3937 }
3938 drm_property_info_populate(b, plane_props, plane->props,
3939 WDRM_PLANE__COUNT, props);
3940 plane->type =
3941 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
3942 props,
3943 WDRM_PLANE_TYPE__COUNT);
Sergi Granellf4456222017-01-12 17:17:32 +00003944
3945 if (drm_plane_populate_formats(plane, kplane, props) < 0) {
3946 drmModeFreeObjectProperties(props);
3947 goto err;
3948 }
3949
Daniel Stone2ba17f42015-05-19 20:02:41 +01003950 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003951 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003952 else {
3953 plane->possible_crtcs = (1 << output->pipe);
3954 plane->plane_id = 0;
3955 plane->count_formats = 1;
Sergi Granellf4456222017-01-12 17:17:32 +00003956 plane->formats[0].format = format;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003957 plane->type = type;
3958 }
3959
3960 if (plane->type == WDRM_PLANE_TYPE__COUNT)
3961 goto err_props;
3962
3963 /* With universal planes, everything is a DRM plane; without
3964 * universal planes, the only DRM planes are overlay planes.
3965 * Everything else is a fake plane. */
3966 if (b->universal_planes) {
3967 assert(kplane);
3968 } else {
3969 if (kplane)
3970 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
3971 else
3972 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
3973 output);
3974 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003975
Pekka Paalanenec272712014-06-05 11:22:25 +03003976 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01003977 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +03003978
3979 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003980
3981err_props:
3982 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
3983err:
3984 drm_plane_state_free(plane->state_cur, true);
3985 free(plane);
3986 return NULL;
3987}
3988
3989/**
3990 * Find, or create, a special-purpose plane
3991 *
3992 * Primary and cursor planes are a special case, in that before universal
3993 * planes, they are driven by non-plane API calls. Without universal plane
3994 * support, the only way to configure a primary plane is via drmModeSetCrtc,
3995 * and the only way to configure a cursor plane is drmModeSetCursor2.
3996 *
3997 * Although they may actually be regular planes in the hardware, without
3998 * universal plane support, these planes are not actually exposed to
3999 * userspace in the regular plane list.
4000 *
4001 * However, for ease of internal tracking, we want to manage all planes
4002 * through the same drm_plane structures. Therefore, when we are running
4003 * without universal plane support, we create fake drm_plane structures
4004 * to track these planes.
4005 *
4006 * @param b DRM backend
4007 * @param output Output to use for plane
4008 * @param type Type of plane
4009 */
4010static struct drm_plane *
4011drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
4012 enum wdrm_plane_type type)
4013{
4014 struct drm_plane *plane;
4015
4016 if (!b->universal_planes) {
4017 uint32_t format;
4018
4019 switch (type) {
4020 case WDRM_PLANE_TYPE_CURSOR:
4021 format = GBM_FORMAT_ARGB8888;
4022 break;
Daniel Stonee2e80132018-01-16 15:37:33 +00004023 case WDRM_PLANE_TYPE_PRIMARY:
4024 /* We don't know what formats the primary plane supports
4025 * before universal planes, so we just assume that the
4026 * GBM format works; however, this isn't set until after
4027 * the output is created. */
4028 format = 0;
4029 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +01004030 default:
4031 assert(!"invalid type in drm_output_find_special_plane");
4032 break;
4033 }
4034
4035 return drm_plane_create(b, NULL, output, type, format);
4036 }
4037
4038 wl_list_for_each(plane, &b->plane_list, link) {
4039 struct drm_output *tmp;
4040 bool found_elsewhere = false;
4041
4042 if (plane->type != type)
4043 continue;
4044 if (!drm_plane_is_available(plane, output))
4045 continue;
4046
4047 /* On some platforms, primary/cursor planes can roam
4048 * between different CRTCs, so make sure we don't claim the
4049 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01004050 wl_list_for_each(tmp, &b->compositor->output_list,
4051 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +00004052 if (tmp->cursor_plane == plane ||
4053 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +01004054 found_elsewhere = true;
4055 break;
4056 }
4057 }
4058
4059 if (found_elsewhere)
4060 continue;
4061
4062 plane->possible_crtcs = (1 << output->pipe);
4063 return plane;
4064 }
4065
4066 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +03004067}
4068
4069/**
4070 * Destroy one DRM plane
4071 *
4072 * Destroy a DRM plane, removing it from screen and releasing its retained
4073 * buffers in the process. The counterpart to drm_plane_create.
4074 *
4075 * @param plane Plane to deallocate (will be freed)
4076 */
4077static void
4078drm_plane_destroy(struct drm_plane *plane)
4079{
Daniel Stone2ba17f42015-05-19 20:02:41 +01004080 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
4081 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
4082 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +00004083 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01004084 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +03004085 weston_plane_release(&plane->base);
4086 wl_list_remove(&plane->link);
4087 free(plane);
4088}
4089
4090/**
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09004091 * Create a drm_plane for virtual output
4092 *
4093 * Call drm_virtual_plane_destroy to clean up the plane.
4094 *
4095 * @param b DRM compositor backend
4096 * @param output Output to create internal plane for
4097 */
4098static struct drm_plane *
4099drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
4100{
4101 struct drm_plane *plane;
4102
4103 /* num of formats is one */
4104 plane = zalloc(sizeof(*plane) + sizeof(plane->formats[0]));
4105 if (!plane) {
4106 weston_log("%s: out of memory\n", __func__);
4107 return NULL;
4108 }
4109
4110 plane->type = WDRM_PLANE_TYPE_PRIMARY;
4111 plane->backend = b;
4112 plane->state_cur = drm_plane_state_alloc(NULL, plane);
4113 plane->state_cur->complete = true;
4114 plane->formats[0].format = output->gbm_format;
4115 plane->count_formats = 1;
Scott Anderson99553752019-01-28 15:40:55 +13004116 if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && b->fb_modifiers) {
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09004117 uint64_t *modifiers = zalloc(sizeof *modifiers);
4118 if (modifiers) {
4119 *modifiers = DRM_FORMAT_MOD_LINEAR;
4120 plane->formats[0].modifiers = modifiers;
4121 plane->formats[0].count_modifiers = 1;
4122 }
4123 }
4124
4125 weston_plane_init(&plane->base, b->compositor, 0, 0);
4126 wl_list_insert(&b->plane_list, &plane->link);
4127
4128 return plane;
4129}
4130
4131/**
4132 * Destroy one DRM plane
4133 *
4134 * @param plane Plane to deallocate (will be freed)
4135 */
4136static void
4137drm_virtual_plane_destroy(struct drm_plane *plane)
4138{
4139 drm_plane_state_free(plane->state_cur, true);
4140 weston_plane_release(&plane->base);
4141 wl_list_remove(&plane->link);
4142 if (plane->formats[0].modifiers)
4143 free(plane->formats[0].modifiers);
4144 free(plane);
4145}
4146
4147/**
Pekka Paalanenec272712014-06-05 11:22:25 +03004148 * Initialise sprites (overlay planes)
4149 *
4150 * Walk the list of provided DRM planes, and add overlay planes.
4151 *
4152 * Call destroy_sprites to free these planes.
4153 *
4154 * @param b DRM compositor backend
4155 */
4156static void
4157create_sprites(struct drm_backend *b)
4158{
4159 drmModePlaneRes *kplane_res;
4160 drmModePlane *kplane;
4161 struct drm_plane *drm_plane;
4162 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +03004163 kplane_res = drmModeGetPlaneResources(b->drm.fd);
4164 if (!kplane_res) {
4165 weston_log("failed to get plane resources: %s\n",
4166 strerror(errno));
4167 return;
4168 }
4169
4170 for (i = 0; i < kplane_res->count_planes; i++) {
4171 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
4172 if (!kplane)
4173 continue;
4174
Daniel Stone2ba17f42015-05-19 20:02:41 +01004175 drm_plane = drm_plane_create(b, kplane, NULL,
4176 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +03004177 drmModeFreePlane(kplane);
4178 if (!drm_plane)
4179 continue;
4180
Daniel Stone085d2b92015-05-21 00:00:57 +01004181 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
4182 weston_compositor_stack_plane(b->compositor,
4183 &drm_plane->base,
4184 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +03004185 }
4186
4187 drmModeFreePlaneResources(kplane_res);
4188}
4189
4190/**
4191 * Clean up sprites (overlay planes)
4192 *
4193 * The counterpart to create_sprites.
4194 *
4195 * @param b DRM compositor backend
4196 */
4197static void
4198destroy_sprites(struct drm_backend *b)
4199{
4200 struct drm_plane *plane, *next;
4201
Daniel Stone085d2b92015-05-21 00:00:57 +01004202 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03004203 drm_plane_destroy(plane);
4204}
4205
Pekka Paalanendc14fd42017-11-10 15:31:39 +02004206static uint32_t
4207drm_refresh_rate_mHz(const drmModeModeInfo *info)
4208{
4209 uint64_t refresh;
4210
4211 /* Calculate higher precision (mHz) refresh rate */
4212 refresh = (info->clock * 1000000LL / info->htotal +
4213 info->vtotal / 2) / info->vtotal;
4214
4215 if (info->flags & DRM_MODE_FLAG_INTERLACE)
4216 refresh *= 2;
4217 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
4218 refresh /= 2;
4219 if (info->vscan > 1)
4220 refresh /= info->vscan;
4221
4222 return refresh;
4223}
4224
Pekka Paalanenec272712014-06-05 11:22:25 +03004225/**
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004226 * Add a mode to output's mode list
4227 *
4228 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
4229 * output's mode list.
4230 *
4231 * @param output DRM output to add mode to
4232 * @param info DRM mode structure to add
4233 * @returns Newly-allocated Weston/DRM mode structure
4234 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004235static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004236drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004237{
4238 struct drm_mode *mode;
4239
4240 mode = malloc(sizeof *mode);
4241 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004242 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004243
4244 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02004245 mode->base.width = info->hdisplay;
4246 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04004247
Pekka Paalanendc14fd42017-11-10 15:31:39 +02004248 mode->base.refresh = drm_refresh_rate_mHz(info);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004249 mode->mode_info = *info;
Daniel Stoned5526cb2016-11-16 10:54:10 +00004250 mode->blob_id = 0;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04004251
4252 if (info->type & DRM_MODE_TYPE_PREFERRED)
4253 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
4254
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304255 mode->base.aspect_ratio = drm_to_weston_mode_aspect_ratio(info->flags);
4256
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004257 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
4258
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004259 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004260}
4261
Daniel Stoned5526cb2016-11-16 10:54:10 +00004262/**
4263 * Destroys a mode, and removes it from the list.
4264 */
4265static void
4266drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
4267{
4268 if (mode->blob_id)
4269 drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
4270 wl_list_remove(&mode->base.link);
4271 free(mode);
4272}
4273
Pekka Paalanen383b3af2017-09-11 14:40:48 +03004274/** Destroy a list of drm_modes
4275 *
4276 * @param backend The backend for releasing mode property blobs.
4277 * @param mode_list The list linked by drm_mode::base.link.
4278 */
4279static void
4280drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
4281{
4282 struct drm_mode *mode, *next;
4283
4284 wl_list_for_each_safe(mode, next, mode_list, base.link)
4285 drm_output_destroy_mode(backend, mode);
4286}
4287
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004288static int
4289drm_subpixel_to_wayland(int drm_value)
4290{
4291 switch (drm_value) {
4292 default:
4293 case DRM_MODE_SUBPIXEL_UNKNOWN:
4294 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
4295 case DRM_MODE_SUBPIXEL_NONE:
4296 return WL_OUTPUT_SUBPIXEL_NONE;
4297 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
4298 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
4299 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
4300 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
4301 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
4302 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
4303 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
4304 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
4305 }
4306}
4307
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004308/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004309static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03004310drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004311{
4312 long brightness, max_brightness, norm;
4313
Pekka Paalanence724242017-09-04 12:21:24 +03004314 brightness = backlight_get_brightness(head->backlight);
4315 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004316
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004317 /* convert it on a scale of 0 to 255 */
4318 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004319
4320 return (uint32_t) norm;
4321}
4322
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004323/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004324static void
4325drm_set_backlight(struct weston_output *output_base, uint32_t value)
4326{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004327 struct drm_output *output = to_drm_output(output_base);
4328 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004329 long max_brightness, new_brightness;
4330
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04004331 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004332 return;
4333
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004334 wl_list_for_each(head, &output->base.head_list, base.output_link) {
4335 if (!head->backlight)
4336 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004337
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004338 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004339
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004340 /* get denormalized value */
4341 new_brightness = (value * max_brightness) / 255;
4342
4343 backlight_set_brightness(head->backlight, new_brightness);
4344 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004345}
4346
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02004347static void
4348drm_output_init_backlight(struct drm_output *output)
4349{
4350 struct weston_head *base;
4351 struct drm_head *head;
4352
4353 output->base.set_backlight = NULL;
4354
4355 wl_list_for_each(base, &output->base.head_list, output_link) {
4356 head = to_drm_head(base);
4357
4358 if (head->backlight) {
4359 weston_log("Initialized backlight for head '%s', device %s\n",
4360 head->base.name, head->backlight->path);
4361
4362 if (!output->base.set_backlight) {
4363 output->base.set_backlight = drm_set_backlight;
4364 output->base.backlight_current =
4365 drm_get_backlight(head);
4366 }
4367 }
4368 }
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02004369}
4370
Daniel Stonea08512f2016-11-08 17:46:10 +00004371/**
4372 * Power output on or off
4373 *
4374 * The DPMS/power level of an output is used to switch it on or off. This
4375 * is DRM's hook for doing so, which can called either as part of repaint,
4376 * or independently of the repaint loop.
4377 *
4378 * If we are called as part of repaint, we simply set the relevant bit in
4379 * state and return.
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09004380 *
4381 * This function is never called on a virtual output.
Daniel Stonea08512f2016-11-08 17:46:10 +00004382 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004383static void
4384drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
4385{
Armin Krezović545dba62016-08-05 15:54:18 +02004386 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00004387 struct drm_backend *b = to_drm_backend(output_base->compositor);
4388 struct drm_pending_state *pending_state = b->repaint_data;
4389 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01004390 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004391
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09004392 assert(!output->virtual);
4393
Daniel Stonea08512f2016-11-08 17:46:10 +00004394 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004395 return;
4396
Daniel Stonea08512f2016-11-08 17:46:10 +00004397 /* If we're being called during the repaint loop, then this is
4398 * simple: discard any previously-generated state, and create a new
4399 * state where we disable everything. When we come to flush, this
4400 * will be applied.
4401 *
4402 * However, we need to be careful: we can be called whilst another
4403 * output is in its repaint cycle (pending_state exists), but our
4404 * output still has an incomplete state application outstanding.
4405 * In that case, we need to wait until that completes. */
4406 if (pending_state && !output->state_last) {
4407 /* The repaint loop already sets DPMS on; we don't need to
4408 * explicitly set it on here, as it will already happen
4409 * whilst applying the repaint state. */
4410 if (level == WESTON_DPMS_ON)
4411 return;
4412
4413 state = drm_pending_state_get_output(pending_state, output);
4414 if (state)
4415 drm_output_state_free(state);
4416 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01004417 return;
4418 }
4419
Daniel Stonea08512f2016-11-08 17:46:10 +00004420 /* As we throw everything away when disabling, just send us back through
4421 * a repaint cycle. */
4422 if (level == WESTON_DPMS_ON) {
4423 if (output->dpms_off_pending)
4424 output->dpms_off_pending = 0;
4425 weston_output_schedule_repaint(output_base);
4426 return;
4427 }
4428
4429 /* If we've already got a request in the pipeline, then we need to
4430 * park our DPMS request until that request has quiesced. */
4431 if (output->state_last) {
4432 output->dpms_off_pending = 1;
4433 return;
4434 }
4435
4436 pending_state = drm_pending_state_alloc(b);
4437 drm_output_get_disable_state(pending_state, output);
4438 ret = drm_pending_state_apply_sync(pending_state);
4439 if (ret != 0)
4440 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004441}
4442
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004443static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004444 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
4445 [DRM_MODE_CONNECTOR_VGA] = "VGA",
4446 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
4447 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
4448 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
4449 [DRM_MODE_CONNECTOR_Composite] = "Composite",
4450 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
4451 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
4452 [DRM_MODE_CONNECTOR_Component] = "Component",
4453 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
4454 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
4455 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
4456 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
4457 [DRM_MODE_CONNECTOR_TV] = "TV",
4458 [DRM_MODE_CONNECTOR_eDP] = "eDP",
Pekka Paalanenab81f152015-08-24 14:27:07 +03004459#ifdef DRM_MODE_CONNECTOR_DSI
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004460 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
4461 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Pekka Paalanenab81f152015-08-24 14:27:07 +03004462#endif
Stefan Agner30e283d2018-08-20 17:11:38 +02004463#ifdef DRM_MODE_CONNECTOR_DPI
4464 [DRM_MODE_CONNECTOR_DPI] = "DPI",
4465#endif
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04004466};
4467
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004468/** Create a name given a DRM connector
4469 *
4470 * \param con The DRM connector whose type and id form the name.
4471 * \return A newly allocate string, or NULL on error. Must be free()'d
4472 * after use.
4473 *
4474 * The name does not identify the DRM display device.
4475 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004476static char *
4477make_connector_name(const drmModeConnector *con)
4478{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004479 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004480 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004481 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004482
4483 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
4484 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004485
4486 if (!type_name)
4487 type_name = "UNNAMED";
4488
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004489 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
4490 if (ret < 0)
4491 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004492
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004493 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004494}
4495
Daniel Stonee4256832017-04-04 17:54:27 +01004496static void drm_output_fini_cursor_egl(struct drm_output *output)
4497{
4498 unsigned int i;
4499
4500 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
4501 drm_fb_unref(output->gbm_cursor_fb[i]);
4502 output->gbm_cursor_fb[i] = NULL;
4503 }
4504}
4505
4506static int
4507drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
4508{
4509 unsigned int i;
4510
Daniel Stone2ba17f42015-05-19 20:02:41 +01004511 /* No point creating cursors if we don't have a plane for them. */
4512 if (!output->cursor_plane)
4513 return 0;
4514
Daniel Stonee4256832017-04-04 17:54:27 +01004515 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
4516 struct gbm_bo *bo;
4517
4518 bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
4519 GBM_FORMAT_ARGB8888,
4520 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
4521 if (!bo)
4522 goto err;
4523
4524 output->gbm_cursor_fb[i] =
Daniel Stonedb10df12016-12-08 13:15:58 +00004525 drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR);
Daniel Stonee4256832017-04-04 17:54:27 +01004526 if (!output->gbm_cursor_fb[i]) {
4527 gbm_bo_destroy(bo);
4528 goto err;
4529 }
4530 }
4531
4532 return 0;
4533
4534err:
4535 weston_log("cursor buffers unavailable, using gl cursors\n");
4536 b->cursors_are_broken = 1;
4537 drm_output_fini_cursor_egl(output);
4538 return -1;
4539}
4540
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004541/* Init output state that depends on gl or gbm */
4542static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004543drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004544{
Derek Foremanc4cfe852015-05-15 12:12:40 -05004545 EGLint format[2] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004546 output->gbm_format,
4547 fallback_format_for(output->gbm_format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05004548 };
Daniel Stonee4256832017-04-04 17:54:27 +01004549 int n_formats = 1;
Daniel Stone244244d2016-11-18 18:02:08 +00004550 struct weston_mode *mode = output->base.current_mode;
4551 struct drm_plane *plane = output->scanout_plane;
4552 unsigned int i;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004553
Philipp Zabel5c8eef12019-03-06 11:12:47 +01004554 assert(output->gbm_surface == NULL);
4555
Daniel Stone244244d2016-11-18 18:02:08 +00004556 for (i = 0; i < plane->count_formats; i++) {
4557 if (plane->formats[i].format == output->gbm_format)
4558 break;
4559 }
4560
4561 if (i == plane->count_formats) {
4562 weston_log("format 0x%x not supported by output %s\n",
4563 output->gbm_format, output->base.name);
4564 return -1;
4565 }
4566
4567#ifdef HAVE_GBM_MODIFIERS
4568 if (plane->formats[i].count_modifiers > 0) {
4569 output->gbm_surface =
4570 gbm_surface_create_with_modifiers(b->gbm,
4571 mode->width,
4572 mode->height,
4573 output->gbm_format,
4574 plane->formats[i].modifiers,
4575 plane->formats[i].count_modifiers);
Daniel Stoneee1d9682019-01-31 00:02:25 +00004576 }
4577
4578 /* If allocating with modifiers fails, try again without. This can
4579 * happen when the KMS display device supports modifiers but the
4580 * GBM driver does not, e.g. the old i915 Mesa driver. */
4581 if (!output->gbm_surface)
Daniel Stone244244d2016-11-18 18:02:08 +00004582#endif
4583 {
4584 output->gbm_surface =
4585 gbm_surface_create(b->gbm, mode->width, mode->height,
4586 output->gbm_format,
Tomohito Esaki718a40b2018-01-31 17:50:15 +09004587 output->gbm_bo_flags);
Daniel Stone244244d2016-11-18 18:02:08 +00004588 }
4589
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004590 if (!output->gbm_surface) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004591 weston_log("failed to create gbm surface\n");
4592 return -1;
4593 }
4594
Derek Foremanc4cfe852015-05-15 12:12:40 -05004595 if (format[1])
4596 n_formats = 2;
Miguel A. Vicoc095cde2016-05-18 17:43:00 +02004597 if (gl_renderer->output_window_create(&output->base,
4598 (EGLNativeWindowType)output->gbm_surface,
4599 output->gbm_surface,
4600 gl_renderer->opaque_attribs,
4601 format,
4602 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004603 weston_log("failed to create gl renderer output state\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004604 gbm_surface_destroy(output->gbm_surface);
Philipp Zabel5c8eef12019-03-06 11:12:47 +01004605 output->gbm_surface = NULL;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004606 return -1;
4607 }
4608
Daniel Stonee4256832017-04-04 17:54:27 +01004609 drm_output_init_cursor_egl(output, b);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004610
4611 return 0;
4612}
4613
Daniel Stone3e661f72016-11-04 17:24:06 +00004614static void
4615drm_output_fini_egl(struct drm_output *output)
4616{
Daniel Stonee2e80132018-01-16 15:37:33 +00004617 struct drm_backend *b = to_drm_backend(output->base.compositor);
4618
4619 /* Destroying the GBM surface will destroy all our GBM buffers,
4620 * regardless of refcount. Ensure we destroy them here. */
4621 if (!b->shutting_down &&
4622 output->scanout_plane->state_cur->fb &&
4623 output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
4624 drm_plane_state_free(output->scanout_plane->state_cur, true);
4625 output->scanout_plane->state_cur =
4626 drm_plane_state_alloc(NULL, output->scanout_plane);
4627 output->scanout_plane->state_cur->complete = true;
4628 }
4629
Daniel Stone3e661f72016-11-04 17:24:06 +00004630 gl_renderer->output_destroy(&output->base);
4631 gbm_surface_destroy(output->gbm_surface);
Philipp Zabel5c8eef12019-03-06 11:12:47 +01004632 output->gbm_surface = NULL;
Daniel Stonee4256832017-04-04 17:54:27 +01004633 drm_output_fini_cursor_egl(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00004634}
4635
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04004636static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004637drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004638{
Hardeningff39efa2013-09-18 23:56:35 +02004639 int w = output->base.current_mode->width;
4640 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004641 uint32_t format = output->gbm_format;
4642 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004643 unsigned int i;
Pekka Paalanendee412d2018-04-23 11:44:58 +02004644 uint32_t flags = 0;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004645
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004646 switch (format) {
4647 case GBM_FORMAT_XRGB8888:
4648 pixman_format = PIXMAN_x8r8g8b8;
4649 break;
4650 case GBM_FORMAT_RGB565:
4651 pixman_format = PIXMAN_r5g6b5;
4652 break;
4653 default:
4654 weston_log("Unsupported pixman format 0x%x\n", format);
4655 return -1;
4656 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004657
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004658 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004659 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004660 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004661 if (!output->dumb[i])
4662 goto err;
4663
4664 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004665 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004666 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00004667 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004668 if (!output->image[i])
4669 goto err;
4670 }
4671
Pekka Paalanendee412d2018-04-23 11:44:58 +02004672 if (b->use_pixman_shadow)
4673 flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
4674
4675 if (pixman_renderer_output_create(&output->base, flags) < 0)
4676 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304677
Pekka Paalanendee412d2018-04-23 11:44:58 +02004678 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
4679 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004680
4681 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02004682 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004683
4684 return 0;
4685
4686err:
4687 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
4688 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01004689 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004690 if (output->image[i])
4691 pixman_image_unref(output->image[i]);
4692
4693 output->dumb[i] = NULL;
4694 output->image[i] = NULL;
4695 }
4696
4697 return -1;
4698}
4699
4700static void
4701drm_output_fini_pixman(struct drm_output *output)
4702{
Daniel Stonee2e80132018-01-16 15:37:33 +00004703 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004704 unsigned int i;
4705
Daniel Stonee2e80132018-01-16 15:37:33 +00004706 /* Destroying the Pixman surface will destroy all our buffers,
4707 * regardless of refcount. Ensure we destroy them here. */
4708 if (!b->shutting_down &&
4709 output->scanout_plane->state_cur->fb &&
4710 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
4711 drm_plane_state_free(output->scanout_plane->state_cur, true);
4712 output->scanout_plane->state_cur =
4713 drm_plane_state_alloc(NULL, output->scanout_plane);
4714 output->scanout_plane->state_cur->complete = true;
4715 }
4716
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004717 pixman_renderer_output_destroy(&output->base);
4718 pixman_region32_fini(&output->previous_damage);
4719
4720 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004721 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01004722 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004723 output->dumb[i] = NULL;
4724 output->image[i] = NULL;
4725 }
4726}
4727
Richard Hughes2b2092a2013-04-24 14:58:02 +01004728static void
4729edid_parse_string(const uint8_t *data, char text[])
4730{
4731 int i;
4732 int replaced = 0;
4733
4734 /* this is always 12 bytes, but we can't guarantee it's null
4735 * terminated or not junk. */
4736 strncpy(text, (const char *) data, 12);
4737
Bryce Harrington9c7de162015-08-28 13:04:26 -07004738 /* guarantee our new string is null-terminated */
4739 text[12] = '\0';
4740
Richard Hughes2b2092a2013-04-24 14:58:02 +01004741 /* remove insane chars */
4742 for (i = 0; text[i] != '\0'; i++) {
4743 if (text[i] == '\n' ||
4744 text[i] == '\r') {
4745 text[i] = '\0';
4746 break;
4747 }
4748 }
4749
4750 /* ensure string is printable */
4751 for (i = 0; text[i] != '\0'; i++) {
4752 if (!isprint(text[i])) {
4753 text[i] = '-';
4754 replaced++;
4755 }
4756 }
4757
4758 /* if the string is random junk, ignore the string */
4759 if (replaced > 4)
4760 text[0] = '\0';
4761}
4762
4763#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
4764#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
4765#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
4766#define EDID_OFFSET_DATA_BLOCKS 0x36
4767#define EDID_OFFSET_LAST_BLOCK 0x6c
4768#define EDID_OFFSET_PNPID 0x08
4769#define EDID_OFFSET_SERIAL 0x0c
4770
4771static int
4772edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
4773{
4774 int i;
4775 uint32_t serial_number;
4776
4777 /* check header */
4778 if (length < 128)
4779 return -1;
4780 if (data[0] != 0x00 || data[1] != 0xff)
4781 return -1;
4782
4783 /* decode the PNP ID from three 5 bit words packed into 2 bytes
4784 * /--08--\/--09--\
4785 * 7654321076543210
4786 * |\---/\---/\---/
4787 * R C1 C2 C3 */
4788 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
4789 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
4790 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
4791 edid->pnp_id[3] = '\0';
4792
4793 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
4794 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
4795 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
4796 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
4797 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
4798 if (serial_number > 0)
4799 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
4800
4801 /* parse EDID data */
4802 for (i = EDID_OFFSET_DATA_BLOCKS;
4803 i <= EDID_OFFSET_LAST_BLOCK;
4804 i += 18) {
4805 /* ignore pixel clock data */
4806 if (data[i] != 0)
4807 continue;
4808 if (data[i+2] != 0)
4809 continue;
4810
4811 /* any useful blocks? */
4812 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
4813 edid_parse_string(&data[i+5],
4814 edid->monitor_name);
4815 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
4816 edid_parse_string(&data[i+5],
4817 edid->serial_number);
4818 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
4819 edid_parse_string(&data[i+5],
4820 edid->eisa_id);
4821 }
4822 }
4823 return 0;
4824}
4825
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004826/** Parse monitor make, model and serial from EDID
4827 *
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004828 * \param head The head whose \c drm_edid to fill in.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004829 * \param props The DRM connector properties to get the EDID from.
Marius Vlada2dace22019-06-12 16:05:44 +03004830 * \param[out] make The monitor make (PNP ID).
4831 * \param[out] model The monitor model (name).
4832 * \param[out] serial_number The monitor serial number.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004833 *
4834 * Each of \c *make, \c *model and \c *serial_number are set only if the
4835 * information is found in the EDID. The pointers they are set to must not
4836 * be free()'d explicitly, instead they get implicitly freed when the
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004837 * \c drm_head is destroyed.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004838 */
Richard Hughes2b2092a2013-04-24 14:58:02 +01004839static void
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004840find_and_parse_output_edid(struct drm_head *head,
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004841 drmModeObjectPropertiesPtr props,
4842 const char **make,
4843 const char **model,
4844 const char **serial_number)
Richard Hughes2b2092a2013-04-24 14:58:02 +01004845{
4846 drmModePropertyBlobPtr edid_blob = NULL;
Daniel Stone02cf4662017-03-03 16:19:39 +00004847 uint32_t blob_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004848 int rc;
4849
Daniel Stone02cf4662017-03-03 16:19:39 +00004850 blob_id =
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004851 drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
Daniel Stone02cf4662017-03-03 16:19:39 +00004852 props, 0);
4853 if (!blob_id)
4854 return;
4855
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004856 edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
Richard Hughes2b2092a2013-04-24 14:58:02 +01004857 if (!edid_blob)
4858 return;
4859
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004860 rc = edid_parse(&head->edid,
Richard Hughes2b2092a2013-04-24 14:58:02 +01004861 edid_blob->data,
4862 edid_blob->length);
4863 if (!rc) {
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004864 if (head->edid.pnp_id[0] != '\0')
4865 *make = head->edid.pnp_id;
4866 if (head->edid.monitor_name[0] != '\0')
4867 *model = head->edid.monitor_name;
4868 if (head->edid.serial_number[0] != '\0')
4869 *serial_number = head->edid.serial_number;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004870 }
4871 drmModeFreePropertyBlob(edid_blob);
4872}
4873
Philipp Zabel61dc4ca2018-08-30 17:39:51 +02004874static bool
4875check_non_desktop(struct drm_head *head, drmModeObjectPropertiesPtr props)
4876{
4877 struct drm_property_info *non_desktop_info =
4878 &head->props_conn[WDRM_CONNECTOR_NON_DESKTOP];
4879
4880 return drm_property_get_value(non_desktop_info, props, 0);
4881}
4882
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004883static int
4884parse_modeline(const char *s, drmModeModeInfo *mode)
4885{
4886 char hsync[16];
4887 char vsync[16];
4888 float fclock;
4889
Pekka Paalanendc4e3c62017-12-05 15:37:41 +02004890 memset(mode, 0, sizeof *mode);
4891
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004892 mode->type = DRM_MODE_TYPE_USERDEF;
4893 mode->hskew = 0;
4894 mode->vscan = 0;
4895 mode->vrefresh = 0;
4896 mode->flags = 0;
4897
Rob Bradford307e09e2013-07-26 16:29:40 +01004898 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004899 &fclock,
4900 &mode->hdisplay,
4901 &mode->hsync_start,
4902 &mode->hsync_end,
4903 &mode->htotal,
4904 &mode->vdisplay,
4905 &mode->vsync_start,
4906 &mode->vsync_end,
4907 &mode->vtotal, hsync, vsync) != 11)
4908 return -1;
4909
4910 mode->clock = fclock * 1000;
Guido Günther92278e02018-06-26 20:40:08 +02004911 if (strcasecmp(hsync, "+hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004912 mode->flags |= DRM_MODE_FLAG_PHSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02004913 else if (strcasecmp(hsync, "-hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004914 mode->flags |= DRM_MODE_FLAG_NHSYNC;
4915 else
4916 return -1;
4917
Guido Günther92278e02018-06-26 20:40:08 +02004918 if (strcasecmp(vsync, "+vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004919 mode->flags |= DRM_MODE_FLAG_PVSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02004920 else if (strcasecmp(vsync, "-vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004921 mode->flags |= DRM_MODE_FLAG_NVSYNC;
4922 else
4923 return -1;
4924
Emmanuel Gil Peyrota62138b2016-05-02 22:40:11 +01004925 snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
4926 mode->hdisplay, mode->vdisplay, fclock);
4927
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004928 return 0;
4929}
4930
Rob Bradford66bd9f52013-06-25 18:56:42 +01004931static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03004932setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01004933 struct weston_output *output,
4934 const char *s)
4935{
4936 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05004937 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004938 struct udev_seat *seat;
4939
Giulio Camuffo954f1832014-10-11 18:27:30 +03004940 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05004941 if (!seat)
4942 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004943
Derek Foreman0720ea32015-07-15 13:00:35 -05004944 seat->base.output = output;
4945
Derek Foreman1281a362015-07-31 16:55:32 -05004946 pointer = weston_seat_get_pointer(&seat->base);
4947 if (pointer)
4948 weston_pointer_clamp(pointer,
4949 &pointer->x,
4950 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01004951 }
4952}
4953
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004954static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03004955drm_output_attach_head(struct weston_output *output_base,
4956 struct weston_head *head_base)
4957{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004958 struct drm_backend *b = to_drm_backend(output_base->compositor);
4959
Pekka Paalanenc112f002017-08-28 16:27:20 +03004960 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
4961 return -1;
4962
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004963 if (!output_base->enabled)
4964 return 0;
4965
4966 /* XXX: ensure the configuration will work.
4967 * This is actually impossible without major infrastructure
4968 * work. */
4969
4970 /* Need to go through modeset to add connectors. */
4971 /* XXX: Ideally we'd do this per-output, not globally. */
4972 /* XXX: Doing it globally, what guarantees another output's update
4973 * will not clear the flag before this output is updated?
4974 */
4975 b->state_invalid = true;
4976
4977 weston_output_schedule_repaint(output_base);
4978
Pekka Paalanenc112f002017-08-28 16:27:20 +03004979 return 0;
4980}
4981
Pekka Paalanen7f853792017-11-29 14:33:33 +02004982static void
4983drm_output_detach_head(struct weston_output *output_base,
4984 struct weston_head *head_base)
4985{
4986 struct drm_backend *b = to_drm_backend(output_base->compositor);
4987
4988 if (!output_base->enabled)
4989 return;
4990
4991 /* Need to go through modeset to drop connectors that should no longer
4992 * be driven. */
4993 /* XXX: Ideally we'd do this per-output, not globally. */
4994 b->state_invalid = true;
4995
4996 weston_output_schedule_repaint(output_base);
4997}
4998
Pekka Paalanenc112f002017-08-28 16:27:20 +03004999static int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005000parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005001{
Pekka Paalanen62a94362018-09-26 14:33:36 +03005002 const struct pixel_format_info *pinfo;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005003
Pekka Paalanen62a94362018-09-26 14:33:36 +03005004 if (s == NULL) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005005 *gbm_format = default_value;
Pekka Paalanen62a94362018-09-26 14:33:36 +03005006
5007 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005008 }
5009
Pekka Paalanen62a94362018-09-26 14:33:36 +03005010 pinfo = pixel_format_get_info_by_drm_name(s);
5011 if (!pinfo) {
5012 weston_log("fatal: unrecognized pixel format: %s\n", s);
5013
5014 return -1;
5015 }
5016
5017 /* GBM formats and DRM formats are identical. */
5018 *gbm_format = pinfo->format;
5019
5020 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005021}
5022
Pekka Paalanenf005f252017-11-10 16:34:39 +02005023static uint32_t
5024u32distance(uint32_t a, uint32_t b)
5025{
5026 if (a < b)
5027 return b - a;
5028 else
5029 return a - b;
5030}
5031
5032/** Choose equivalent mode
5033 *
5034 * If the two modes are not equivalent, return NULL.
5035 * Otherwise return the mode that is more likely to work in place of both.
5036 *
5037 * None of the fuzzy matching criteria in this function have any justification.
5038 *
5039 * typedef struct _drmModeModeInfo {
5040 * uint32_t clock;
5041 * uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
5042 * uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
5043 *
5044 * uint32_t vrefresh;
5045 *
5046 * uint32_t flags;
5047 * uint32_t type;
5048 * char name[DRM_DISPLAY_MODE_LEN];
5049 * } drmModeModeInfo, *drmModeModeInfoPtr;
5050 */
5051static const drmModeModeInfo *
5052drm_mode_pick_equivalent(const drmModeModeInfo *a, const drmModeModeInfo *b)
5053{
5054 uint32_t refresh_a, refresh_b;
5055
5056 if (a->hdisplay != b->hdisplay || a->vdisplay != b->vdisplay)
5057 return NULL;
5058
5059 if (a->flags != b->flags)
5060 return NULL;
5061
5062 /* kHz */
5063 if (u32distance(a->clock, b->clock) > 500)
5064 return NULL;
5065
5066 refresh_a = drm_refresh_rate_mHz(a);
5067 refresh_b = drm_refresh_rate_mHz(b);
5068 if (u32distance(refresh_a, refresh_b) > 50)
5069 return NULL;
5070
5071 if ((a->type ^ b->type) & DRM_MODE_TYPE_PREFERRED) {
5072 if (a->type & DRM_MODE_TYPE_PREFERRED)
5073 return a;
5074 else
5075 return b;
5076 }
5077
5078 return a;
5079}
5080
5081/* If the given mode info is not already in the list, add it.
5082 * If it is in the list, either keep the existing or replace it,
5083 * depending on which one is "better".
5084 */
5085static int
5086drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
5087{
5088 struct weston_mode *base;
5089 struct drm_mode *mode;
5090 struct drm_backend *backend;
5091 const drmModeModeInfo *chosen = NULL;
5092
5093 assert(info);
5094
5095 wl_list_for_each(base, &output->base.mode_list, link) {
5096 mode = to_drm_mode(base);
5097 chosen = drm_mode_pick_equivalent(&mode->mode_info, info);
5098 if (chosen)
5099 break;
5100 }
5101
5102 if (chosen == info) {
5103 backend = to_drm_backend(output->base.compositor);
5104 drm_output_destroy_mode(backend, mode);
5105 chosen = NULL;
5106 }
5107
5108 if (!chosen) {
5109 mode = drm_output_add_mode(output, info);
5110 if (!mode)
5111 return -1;
5112 }
5113 /* else { the equivalent mode is already in the list } */
5114
5115 return 0;
5116}
5117
Pekka Paalanen4be24852017-09-11 15:01:12 +03005118/** Rewrite the output's mode list
5119 *
5120 * @param output The output.
5121 * @return 0 on success, -1 on failure.
5122 *
5123 * Destroy all existing modes in the list, and reconstruct a new list from
5124 * scratch, based on the currently attached heads.
5125 *
5126 * On failure the output's mode list may contain some modes.
5127 */
5128static int
5129drm_output_update_modelist_from_heads(struct drm_output *output)
5130{
5131 struct drm_backend *backend = to_drm_backend(output->base.compositor);
5132 struct weston_head *head_base;
5133 struct drm_head *head;
Pekka Paalanen4be24852017-09-11 15:01:12 +03005134 int i;
Pekka Paalanenf005f252017-11-10 16:34:39 +02005135 int ret;
Pekka Paalanen4be24852017-09-11 15:01:12 +03005136
5137 assert(!output->base.enabled);
5138
5139 drm_mode_list_destroy(backend, &output->base.mode_list);
5140
Pekka Paalanenf005f252017-11-10 16:34:39 +02005141 wl_list_for_each(head_base, &output->base.head_list, output_link) {
5142 head = to_drm_head(head_base);
5143 for (i = 0; i < head->connector->count_modes; i++) {
5144 ret = drm_output_try_add_mode(output,
5145 &head->connector->modes[i]);
5146 if (ret < 0)
5147 return -1;
5148 }
Pekka Paalanen4be24852017-09-11 15:01:12 +03005149 }
5150
5151 return 0;
5152}
5153
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005154/**
5155 * Choose suitable mode for an output
5156 *
5157 * Find the most suitable mode to use for initial setup (or reconfiguration on
5158 * hotplug etc) for a DRM output.
5159 *
Marius Vlada2dace22019-06-12 16:05:44 +03005160 * @param backend the DRM backend
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005161 * @param output DRM output to choose mode for
Marius Vlada2dace22019-06-12 16:05:44 +03005162 * @param mode Strategy and preference to use when choosing mode
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005163 * @param modeline Manually-entered mode (may be NULL)
Marius Vlada2dace22019-06-12 16:05:44 +03005164 * @param current_mode Mode currently being displayed on this output
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005165 * @returns A mode from the output's mode list, or NULL if none available
5166 */
5167static struct drm_mode *
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005168drm_output_choose_initial_mode(struct drm_backend *backend,
5169 struct drm_output *output,
5170 enum weston_drm_backend_output_mode mode,
Armin Krezović08368132016-09-30 14:11:05 +02005171 const char *modeline,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005172 const drmModeModeInfo *current_mode)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005173{
5174 struct drm_mode *preferred = NULL;
5175 struct drm_mode *current = NULL;
5176 struct drm_mode *configured = NULL;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305177 struct drm_mode *config_fall_back = NULL;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005178 struct drm_mode *best = NULL;
5179 struct drm_mode *drm_mode;
Armin Krezović08368132016-09-30 14:11:05 +02005180 drmModeModeInfo drm_modeline;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005181 int32_t width = 0;
5182 int32_t height = 0;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005183 uint32_t refresh = 0;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305184 uint32_t aspect_width = 0;
5185 uint32_t aspect_height = 0;
5186 enum weston_mode_aspect_ratio aspect_ratio = WESTON_MODE_PIC_AR_NONE;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005187 int n;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005188
Armin Krezović08368132016-09-30 14:11:05 +02005189 if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305190 n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height,
5191 &refresh, &aspect_width, &aspect_height);
5192 if (backend->aspect_ratio_supported && n == 5) {
5193 if (aspect_width == 4 && aspect_height == 3)
5194 aspect_ratio = WESTON_MODE_PIC_AR_4_3;
5195 else if (aspect_width == 16 && aspect_height == 9)
5196 aspect_ratio = WESTON_MODE_PIC_AR_16_9;
5197 else if (aspect_width == 64 && aspect_height == 27)
5198 aspect_ratio = WESTON_MODE_PIC_AR_64_27;
5199 else if (aspect_width == 256 && aspect_height == 135)
5200 aspect_ratio = WESTON_MODE_PIC_AR_256_135;
5201 else
5202 weston_log("Invalid modeline \"%s\" for output %s\n",
5203 modeline, output->base.name);
5204 }
5205 if (n != 2 && n != 3 && n != 5) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005206 width = -1;
5207
Armin Krezović08368132016-09-30 14:11:05 +02005208 if (parse_modeline(modeline, &drm_modeline) == 0) {
5209 configured = drm_output_add_mode(output, &drm_modeline);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005210 if (!configured)
5211 return NULL;
5212 } else {
5213 weston_log("Invalid modeline \"%s\" for output %s\n",
Armin Krezović08368132016-09-30 14:11:05 +02005214 modeline, output->base.name);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005215 }
5216 }
5217 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005218
5219 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005220 if (width == drm_mode->base.width &&
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005221 height == drm_mode->base.height &&
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305222 (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
5223 if (!backend->aspect_ratio_supported ||
5224 aspect_ratio == drm_mode->base.aspect_ratio)
5225 configured = drm_mode;
5226 else
5227 config_fall_back = drm_mode;
5228 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005229
comic fans7a5c5622016-03-17 14:29:27 +02005230 if (memcmp(current_mode, &drm_mode->mode_info,
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005231 sizeof *current_mode) == 0)
5232 current = drm_mode;
5233
5234 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
5235 preferred = drm_mode;
5236
5237 best = drm_mode;
5238 }
5239
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005240 if (current == NULL && current_mode->clock != 0) {
5241 current = drm_output_add_mode(output, current_mode);
5242 if (!current)
5243 return NULL;
5244 }
5245
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005246 if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005247 configured = current;
5248
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005249 if (configured)
5250 return configured;
5251
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305252 if (config_fall_back)
5253 return config_fall_back;
5254
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005255 if (preferred)
5256 return preferred;
5257
5258 if (current)
5259 return current;
5260
5261 if (best)
5262 return best;
5263
5264 weston_log("no available modes for %s\n", output->base.name);
5265 return NULL;
5266}
5267
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005268static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005269drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005270{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005271 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005272 drmModeEncoder *encoder;
5273 drmModeCrtc *crtc;
5274
5275 /* Get the current mode on the crtc that's currently driving
5276 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005277 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005278 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005279 head->inherited_crtc_id = encoder->crtc_id;
5280
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005281 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
5282 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005283
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005284 if (crtc == NULL)
5285 return -1;
5286 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02005287 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005288 drmModeFreeCrtc(crtc);
5289 }
5290
5291 return 0;
5292}
5293
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005294static int
Armin Krezović08368132016-09-30 14:11:05 +02005295drm_output_set_mode(struct weston_output *base,
5296 enum weston_drm_backend_output_mode mode,
5297 const char *modeline)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005298{
Armin Krezović08368132016-09-30 14:11:05 +02005299 struct drm_output *output = to_drm_output(base);
5300 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005301 struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005302
Armin Krezović445b41b2016-10-09 23:48:16 +02005303 struct drm_mode *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005304
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09005305 if (output->virtual)
5306 return -1;
5307
Pekka Paalanen4be24852017-09-11 15:01:12 +03005308 if (drm_output_update_modelist_from_heads(output) < 0)
5309 return -1;
5310
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005311 current = drm_output_choose_initial_mode(b, output, mode, modeline,
5312 &head->inherited_mode);
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005313 if (!current)
Armin Krezović445b41b2016-10-09 23:48:16 +02005314 return -1;
Armin Krezović08368132016-09-30 14:11:05 +02005315
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005316 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02005317 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04005318
Armin Krezović08368132016-09-30 14:11:05 +02005319 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
5320 output->base.native_mode = output->base.current_mode;
5321 output->base.native_scale = output->base.current_scale;
5322
Armin Krezović08368132016-09-30 14:11:05 +02005323 return 0;
Armin Krezović08368132016-09-30 14:11:05 +02005324}
5325
5326static void
5327drm_output_set_gbm_format(struct weston_output *base,
5328 const char *gbm_format)
5329{
5330 struct drm_output *output = to_drm_output(base);
5331 struct drm_backend *b = to_drm_backend(base->compositor);
5332
5333 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
5334 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00005335
5336 /* Without universal planes, we can't discover which formats are
5337 * supported by the primary plane; we just hope that the GBM format
5338 * works. */
5339 if (!b->universal_planes)
Sergi Granellf4456222017-01-12 17:17:32 +00005340 output->scanout_plane->formats[0].format = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02005341}
5342
5343static void
5344drm_output_set_seat(struct weston_output *base,
5345 const char *seat)
5346{
5347 struct drm_output *output = to_drm_output(base);
5348 struct drm_backend *b = to_drm_backend(base->compositor);
5349
5350 setup_output_seat_constraint(b, &output->base,
5351 seat ? seat : "");
5352}
5353
5354static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005355drm_output_init_gamma_size(struct drm_output *output)
5356{
5357 struct drm_backend *backend = to_drm_backend(output->base.compositor);
5358 drmModeCrtc *crtc;
5359
5360 assert(output->base.compositor);
5361 assert(output->crtc_id != 0);
5362 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
5363 if (!crtc)
5364 return -1;
5365
5366 output->base.gamma_size = crtc->gamma_size;
5367
5368 drmModeFreeCrtc(crtc);
5369
5370 return 0;
5371}
5372
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005373static uint32_t
5374drm_head_get_possible_crtcs_mask(struct drm_head *head)
5375{
5376 uint32_t possible_crtcs = 0;
5377 drmModeEncoder *encoder;
5378 int i;
5379
5380 for (i = 0; i < head->connector->count_encoders; i++) {
5381 encoder = drmModeGetEncoder(head->backend->drm.fd,
5382 head->connector->encoders[i]);
5383 if (!encoder)
5384 continue;
5385
5386 possible_crtcs |= encoder->possible_crtcs;
5387 drmModeFreeEncoder(encoder);
5388 }
5389
5390 return possible_crtcs;
5391}
5392
5393static int
5394drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
5395{
5396 int i;
5397
5398 for (i = 0; i < resources->count_crtcs; i++) {
5399 if (resources->crtcs[i] == crtc_id)
5400 return i;
5401 }
5402
5403 assert(0 && "unknown crtc id");
5404 return -1;
5405}
5406
5407/** Pick a CRTC that might be able to drive all attached connectors
5408 *
5409 * @param output The output whose attached heads to include.
5410 * @param resources The DRM KMS resources.
5411 * @return CRTC index, or -1 on failure or not found.
5412 */
5413static int
5414drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
5415{
5416 struct drm_backend *backend;
5417 struct weston_head *base;
5418 struct drm_head *head;
5419 uint32_t possible_crtcs = 0xffffffff;
5420 int existing_crtc[32];
5421 unsigned j, n = 0;
5422 uint32_t crtc_id;
5423 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005424 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005425 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005426 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005427
5428 backend = to_drm_backend(output->base.compositor);
5429
5430 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
5431 * because it is more often set wrong than not in the kernel. */
5432
5433 /* Accumulate a mask of possible crtcs and find existing routings. */
5434 wl_list_for_each(base, &output->base.head_list, output_link) {
5435 head = to_drm_head(base);
5436
5437 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
5438
5439 crtc_id = head->inherited_crtc_id;
5440 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
5441 existing_crtc[n++] = drm_crtc_get_index(resources,
5442 crtc_id);
5443 }
5444
5445 /* Find a crtc that could drive each connector individually at least,
5446 * and prefer existing routings. */
5447 for (i = 0; i < resources->count_crtcs; i++) {
5448 crtc_id = resources->crtcs[i];
5449
5450 /* Could the crtc not drive each connector? */
5451 if (!(possible_crtcs & (1 << i)))
5452 continue;
5453
5454 /* Is the crtc already in use? */
5455 if (drm_output_find_by_crtc(backend, crtc_id))
5456 continue;
5457
5458 /* Try to preserve the existing CRTC -> connector routing;
5459 * it makes initialisation faster, and also since we have a
5460 * very dumb picking algorithm, may preserve a better
5461 * choice. */
5462 for (j = 0; j < n; j++) {
5463 if (existing_crtc[j] == i)
5464 return i;
5465 }
5466
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005467 /* Check if any other head had existing routing to this CRTC.
5468 * If they did, this is not the best CRTC as it might be needed
5469 * for another output we haven't enabled yet. */
5470 match = false;
5471 wl_list_for_each(base, &backend->compositor->head_list,
5472 compositor_link) {
5473 head = to_drm_head(base);
5474
5475 if (head->base.output == &output->base)
5476 continue;
5477
5478 if (weston_head_is_enabled(&head->base))
5479 continue;
5480
5481 if (head->inherited_crtc_id == crtc_id) {
5482 match = true;
5483 break;
5484 }
5485 }
5486 if (!match)
5487 best_crtc_index = i;
5488
5489 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005490 }
5491
5492 if (best_crtc_index != -1)
5493 return best_crtc_index;
5494
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005495 if (fallback_crtc_index != -1)
5496 return fallback_crtc_index;
5497
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005498 /* Likely possible_crtcs was empty due to asking for clones,
5499 * but since the DRM documentation says the kernel lies, let's
5500 * pick one crtc anyway. Trial and error is the only way to
5501 * be sure if something doesn't work. */
5502
5503 /* First pick any existing assignment. */
5504 for (j = 0; j < n; j++) {
5505 crtc_id = resources->crtcs[existing_crtc[j]];
5506 if (!drm_output_find_by_crtc(backend, crtc_id))
5507 return existing_crtc[j];
5508 }
5509
5510 /* Otherwise pick any available crtc. */
5511 for (i = 0; i < resources->count_crtcs; i++) {
5512 crtc_id = resources->crtcs[i];
5513
5514 if (!drm_output_find_by_crtc(backend, crtc_id))
5515 return i;
5516 }
5517
5518 return -1;
5519}
5520
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005521/** Allocate a CRTC for the output
5522 *
5523 * @param output The output with no allocated CRTC.
5524 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005525 * @return 0 on success, -1 on failure.
5526 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005527 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005528 * for the output, and loads the CRTC properties.
5529 *
5530 * Populates the cursor and scanout planes.
5531 *
5532 * On failure, the output remains without a CRTC.
5533 */
5534static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005535drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005536{
5537 struct drm_backend *b = to_drm_backend(output->base.compositor);
5538 drmModeObjectPropertiesPtr props;
5539 int i;
5540
5541 assert(output->crtc_id == 0);
5542
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005543 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005544 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005545 weston_log("Output '%s': No available CRTCs.\n",
5546 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005547 return -1;
5548 }
5549
5550 output->crtc_id = resources->crtcs[i];
5551 output->pipe = i;
5552
5553 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
5554 DRM_MODE_OBJECT_CRTC);
5555 if (!props) {
5556 weston_log("failed to get CRTC properties\n");
5557 goto err_crtc;
5558 }
5559 drm_property_info_populate(b, crtc_props, output->props_crtc,
5560 WDRM_CRTC__COUNT, props);
5561 drmModeFreeObjectProperties(props);
5562
5563 output->scanout_plane =
5564 drm_output_find_special_plane(b, output,
5565 WDRM_PLANE_TYPE_PRIMARY);
5566 if (!output->scanout_plane) {
5567 weston_log("Failed to find primary plane for output %s\n",
5568 output->base.name);
5569 goto err_crtc;
5570 }
5571
5572 /* Failing to find a cursor plane is not fatal, as we'll fall back
5573 * to software cursor. */
5574 output->cursor_plane =
5575 drm_output_find_special_plane(b, output,
5576 WDRM_PLANE_TYPE_CURSOR);
5577
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005578 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
5579
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005580 return 0;
5581
5582err_crtc:
5583 output->crtc_id = 0;
5584 output->pipe = 0;
5585
5586 return -1;
5587}
5588
5589/** Free the CRTC from the output
5590 *
5591 * @param output The output whose CRTC to deallocate.
5592 *
5593 * The CRTC reserved for the given output becomes free to use again.
5594 */
5595static void
5596drm_output_fini_crtc(struct drm_output *output)
5597{
5598 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005599 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005600
5601 if (!b->universal_planes && !b->shutting_down) {
5602 /* With universal planes, the 'special' planes are allocated at
5603 * startup, freed at shutdown, and live on the plane list in
5604 * between. We want the planes to continue to exist and be freed
5605 * up for other outputs.
5606 *
5607 * Without universal planes, our special planes are
5608 * pseudo-planes allocated at output creation, freed at output
5609 * destruction, and not usable by other outputs.
5610 *
5611 * On the other hand, if the compositor is already shutting down,
5612 * the plane has already been destroyed.
5613 */
5614 if (output->cursor_plane)
5615 drm_plane_destroy(output->cursor_plane);
5616 if (output->scanout_plane)
5617 drm_plane_destroy(output->scanout_plane);
5618 }
5619
5620 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005621
5622 assert(output->crtc_id != 0);
5623
5624 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
5625 *unused = output->crtc_id;
5626
5627 /* Force resetting unused CRTCs */
5628 b->state_invalid = true;
5629
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005630 output->crtc_id = 0;
5631 output->cursor_plane = NULL;
5632 output->scanout_plane = NULL;
5633}
5634
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005635static void
5636drm_output_print_modes(struct drm_output *output)
5637{
5638 struct weston_mode *m;
5639 struct drm_mode *dm;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305640 const char *aspect_ratio;
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005641
5642 wl_list_for_each(m, &output->base.mode_list, link) {
5643 dm = to_drm_mode(m);
5644
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305645 aspect_ratio = aspect_ratio_to_string(m->aspect_ratio);
5646 weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s%s, %.1f MHz\n",
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005647 m->width, m->height, m->refresh / 1000.0,
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305648 aspect_ratio,
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005649 m->flags & WL_OUTPUT_MODE_PREFERRED ?
5650 ", preferred" : "",
5651 m->flags & WL_OUTPUT_MODE_CURRENT ?
5652 ", current" : "",
5653 dm->mode_info.clock / 1000.0);
5654 }
5655}
5656
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005657static int
Armin Krezović08368132016-09-30 14:11:05 +02005658drm_output_enable(struct weston_output *base)
5659{
5660 struct drm_output *output = to_drm_output(base);
5661 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005662 drmModeRes *resources;
5663 int ret;
5664
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09005665 assert(!output->virtual);
5666
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005667 resources = drmModeGetResources(b->drm.fd);
5668 if (!resources) {
5669 weston_log("drmModeGetResources failed\n");
5670 return -1;
5671 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005672 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005673 drmModeFreeResources(resources);
5674 if (ret < 0)
5675 return -1;
5676
5677 if (drm_output_init_gamma_size(output) < 0)
5678 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02005679
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005680 if (b->pageflip_timeout)
5681 drm_output_pageflip_timer_create(output);
5682
Giulio Camuffo954f1832014-10-11 18:27:30 +03005683 if (b->use_pixman) {
5684 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005685 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005686 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005687 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03005688 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005689 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005690 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04005691 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04005692
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02005693 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005694
Jonas Ådahle5a12252013-04-05 23:07:11 +02005695 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05005696 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05005697 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005698 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08005699 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01005700 output->base.set_gamma = drm_output_set_gamma;
5701
Daniel Stone2ba17f42015-05-19 20:02:41 +01005702 if (output->cursor_plane)
5703 weston_compositor_stack_plane(b->compositor,
5704 &output->cursor_plane->base,
5705 NULL);
5706 else
5707 b->cursors_are_broken = 1;
5708
Daniel Stonee2e80132018-01-16 15:37:33 +00005709 weston_compositor_stack_plane(b->compositor,
5710 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03005711 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02005712
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005713 weston_log("Output %s (crtc %d) video modes:\n",
5714 output->base.name, output->crtc_id);
5715 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04005716
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005717 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01005718
Daniel Stone02cf4662017-03-03 16:19:39 +00005719err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005720 drm_output_fini_crtc(output);
5721
David Herrmann0f0d54e2011-12-08 17:05:45 +01005722 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005723}
5724
Jesse Barnes58ef3792012-02-23 09:45:49 -05005725static void
Armin Krezović08368132016-09-30 14:11:05 +02005726drm_output_deinit(struct weston_output *base)
5727{
5728 struct drm_output *output = to_drm_output(base);
5729 struct drm_backend *b = to_drm_backend(base->compositor);
5730
Daniel Stone3e661f72016-11-04 17:24:06 +00005731 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02005732 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00005733 else
5734 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02005735
Daniel Stone2ba17f42015-05-19 20:02:41 +01005736 /* Since our planes are no longer in use anywhere, remove their base
5737 * weston_plane's link from the plane stacking list, unless we're
5738 * shutting down, in which case the plane has already been
5739 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00005740 if (!b->shutting_down) {
5741 wl_list_remove(&output->scanout_plane->base.link);
5742 wl_list_init(&output->scanout_plane->base.link);
5743
5744 if (output->cursor_plane) {
5745 wl_list_remove(&output->cursor_plane->base.link);
5746 wl_list_init(&output->cursor_plane->base.link);
5747 /* Turn off hardware cursor */
5748 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
5749 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01005750 }
Daniel Stone087ddf02017-02-14 17:51:30 +00005751
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005752 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02005753}
5754
5755static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03005756drm_head_destroy(struct drm_head *head);
5757
5758static void
Armin Krezović08368132016-09-30 14:11:05 +02005759drm_output_destroy(struct weston_output *base)
5760{
5761 struct drm_output *output = to_drm_output(base);
5762 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005763
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09005764 assert(!output->virtual);
5765
Daniel Stone31838bf2019-06-17 11:23:25 +01005766 if (output->page_flip_pending || output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005767 output->destroy_pending = 1;
5768 weston_log("destroy output while page flip pending\n");
5769 return;
5770 }
5771
5772 if (output->base.enabled)
5773 drm_output_deinit(&output->base);
5774
Pekka Paalanen383b3af2017-09-11 14:40:48 +03005775 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02005776
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005777 if (output->pageflip_timer)
5778 wl_event_source_remove(output->pageflip_timer);
5779
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03005780 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02005781
Daniel Stone7b2ddac2016-11-11 19:11:49 +00005782 assert(!output->state_last);
5783 drm_output_state_free(output->state_cur);
5784
Armin Krezović08368132016-09-30 14:11:05 +02005785 free(output);
5786}
5787
5788static int
5789drm_output_disable(struct weston_output *base)
5790{
5791 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02005792
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09005793 assert(!output->virtual);
5794
Daniel Stone31838bf2019-06-17 11:23:25 +01005795 if (output->page_flip_pending || output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005796 output->disable_pending = 1;
5797 return -1;
5798 }
5799
Daniel Stonea08512f2016-11-08 17:46:10 +00005800 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00005801
Armin Krezović08368132016-09-30 14:11:05 +02005802 if (output->base.enabled)
5803 drm_output_deinit(&output->base);
5804
5805 output->disable_pending = 0;
5806
Armin Krezović08368132016-09-30 14:11:05 +02005807 return 0;
5808}
5809
5810/**
Daniel Stone087ddf02017-02-14 17:51:30 +00005811 * Update the list of unused connectors and CRTCs
5812 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03005813 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00005814 *
5815 * @param b Weston backend structure
5816 * @param resources DRM resources for this device
5817 */
5818static void
5819drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
5820{
5821 int i;
5822
Daniel Stone087ddf02017-02-14 17:51:30 +00005823 wl_array_release(&b->unused_crtcs);
5824 wl_array_init(&b->unused_crtcs);
5825
5826 for (i = 0; i < resources->count_crtcs; i++) {
5827 struct drm_output *output;
5828 uint32_t *crtc_id;
5829
5830 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
5831 if (output && output->base.enabled)
5832 continue;
5833
5834 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
5835 *crtc_id = resources->crtcs[i];
5836 }
5837}
5838
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005839/** Replace connector data and monitor information
5840 *
5841 * @param head The head to update.
5842 * @param connector The connector data to be owned by the head, must match
5843 * the head's connector ID.
5844 * @return 0 on success, -1 on failure.
5845 *
5846 * Takes ownership of @c connector on success, not on failure.
5847 *
5848 * May schedule a heads changed call.
5849 */
5850static int
5851drm_head_assign_connector_info(struct drm_head *head,
5852 drmModeConnector *connector)
5853{
5854 drmModeObjectProperties *props;
5855 const char *make = "unknown";
5856 const char *model = "unknown";
5857 const char *serial_number = "unknown";
5858
5859 assert(connector);
5860 assert(head->connector_id == connector->connector_id);
5861
5862 props = drmModeObjectGetProperties(head->backend->drm.fd,
5863 head->connector_id,
5864 DRM_MODE_OBJECT_CONNECTOR);
5865 if (!props) {
5866 weston_log("Error: failed to get connector '%s' properties\n",
5867 head->base.name);
5868 return -1;
5869 }
5870
5871 if (head->connector)
5872 drmModeFreeConnector(head->connector);
5873 head->connector = connector;
5874
5875 drm_property_info_populate(head->backend, connector_props,
5876 head->props_conn,
5877 WDRM_CONNECTOR__COUNT, props);
5878 find_and_parse_output_edid(head, props, &make, &model, &serial_number);
5879 weston_head_set_monitor_strings(&head->base, make, model, serial_number);
Philipp Zabel61dc4ca2018-08-30 17:39:51 +02005880 weston_head_set_non_desktop(&head->base,
5881 check_non_desktop(head, props));
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005882 weston_head_set_subpixel(&head->base,
5883 drm_subpixel_to_wayland(head->connector->subpixel));
5884
5885 weston_head_set_physical_size(&head->base, head->connector->mmWidth,
5886 head->connector->mmHeight);
5887
5888 drmModeFreeObjectProperties(props);
5889
5890 /* Unknown connection status is assumed disconnected. */
5891 weston_head_set_connection_status(&head->base,
5892 head->connector->connection == DRM_MODE_CONNECTED);
5893
5894 return 0;
5895}
5896
Pekka Paalanen456dc732017-11-09 15:10:11 +02005897static void
5898drm_head_log_info(struct drm_head *head, const char *msg)
5899{
5900 if (head->base.connected) {
5901 weston_log("DRM: head '%s' %s, connector %d is connected, "
5902 "EDID make '%s', model '%s', serial '%s'\n",
5903 head->base.name, msg, head->connector_id,
5904 head->base.make, head->base.model,
5905 head->base.serial_number ?: "");
5906 } else {
5907 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
5908 head->base.name, msg, head->connector_id);
5909 }
5910}
5911
Pekka Paalanend2e62422017-09-08 15:48:07 +03005912/** Update connector and monitor information
5913 *
5914 * @param head The head to update.
5915 *
5916 * Re-reads the DRM property lists for the connector and updates monitor
5917 * information and connection status. This may schedule a heads changed call
5918 * to the user.
5919 */
5920static void
5921drm_head_update_info(struct drm_head *head)
5922{
5923 drmModeConnector *connector;
5924
5925 connector = drmModeGetConnector(head->backend->drm.fd,
5926 head->connector_id);
5927 if (!connector) {
5928 weston_log("DRM: getting connector info for '%s' failed.\n",
5929 head->base.name);
5930 return;
5931 }
5932
5933 if (drm_head_assign_connector_info(head, connector) < 0)
5934 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005935
5936 if (head->base.device_changed)
5937 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03005938}
5939
Daniel Stone087ddf02017-02-14 17:51:30 +00005940/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03005941 * Create a Weston head for a connector
5942 *
5943 * Given a DRM connector, create a matching drm_head structure and add it
5944 * to Weston's head list.
5945 *
Marius Vlada2dace22019-06-12 16:05:44 +03005946 * @param backend Weston backend structure
Pekka Paalanenc112f002017-08-28 16:27:20 +03005947 * @param connector_id DRM connector ID for the head
5948 * @param drm_device udev device pointer
5949 * @returns The new head, or NULL on failure.
5950 */
5951static struct drm_head *
5952drm_head_create(struct drm_backend *backend, uint32_t connector_id,
5953 struct udev_device *drm_device)
5954{
5955 struct drm_head *head;
5956 drmModeConnector *connector;
5957 char *name;
5958
5959 head = zalloc(sizeof *head);
5960 if (!head)
5961 return NULL;
5962
5963 connector = drmModeGetConnector(backend->drm.fd, connector_id);
5964 if (!connector)
5965 goto err_alloc;
5966
5967 name = make_connector_name(connector);
5968 if (!name)
5969 goto err_alloc;
5970
5971 weston_head_init(&head->base, name);
5972 free(name);
5973
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005974 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005975 head->backend = backend;
5976
Pekka Paalanence724242017-09-04 12:21:24 +03005977 head->backlight = backlight_init(drm_device, connector->connector_type);
5978
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005979 if (drm_head_assign_connector_info(head, connector) < 0)
5980 goto err_init;
5981
5982 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
5983 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
5984 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03005985
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005986 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005987 weston_log("Failed to retrieve current mode from connector %d.\n",
5988 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02005989 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005990 }
5991
Pekka Paalanenc112f002017-08-28 16:27:20 +03005992 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005993 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03005994
5995 return head;
5996
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005997err_init:
5998 weston_head_release(&head->base);
5999
Pekka Paalanenc112f002017-08-28 16:27:20 +03006000err_alloc:
6001 if (connector)
6002 drmModeFreeConnector(connector);
6003
6004 free(head);
6005
6006 return NULL;
6007}
6008
6009static void
6010drm_head_destroy(struct drm_head *head)
6011{
6012 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03006013
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006014 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
6015 drmModeFreeConnector(head->connector);
6016
Pekka Paalanence724242017-09-04 12:21:24 +03006017 if (head->backlight)
6018 backlight_destroy(head->backlight);
6019
Pekka Paalanenc112f002017-08-28 16:27:20 +03006020 free(head);
6021}
6022
6023/**
Armin Krezović08368132016-09-30 14:11:05 +02006024 * Create a Weston output structure
6025 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03006026 * Create an "empty" drm_output. This is the implementation of
6027 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02006028 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03006029 * Creating an output is usually followed by drm_output_attach_head()
6030 * and drm_output_enable() to make use of it.
6031 *
6032 * @param compositor The compositor instance.
6033 * @param name Name for the new output.
6034 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02006035 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03006036static struct weston_output *
6037drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02006038{
Pekka Paalanend2e62422017-09-08 15:48:07 +03006039 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02006040 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02006041
Armin Krezović08368132016-09-30 14:11:05 +02006042 output = zalloc(sizeof *output);
6043 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03006044 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02006045
Daniel Stone64dbbee2018-07-20 19:00:06 +01006046 output->backend = b;
Tomohito Esaki718a40b2018-01-31 17:50:15 +09006047 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Daniel Stone64dbbee2018-07-20 19:00:06 +01006048
Pekka Paalanend2e62422017-09-08 15:48:07 +03006049 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006050
Armin Krezović08368132016-09-30 14:11:05 +02006051 output->base.enable = drm_output_enable;
6052 output->base.destroy = drm_output_destroy;
6053 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03006054 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02006055 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02006056
6057 output->destroy_pending = 0;
6058 output->disable_pending = 0;
Armin Krezović08368132016-09-30 14:11:05 +02006059
Pekka Paalanen01f60212017-03-24 15:39:24 +02006060 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03006061
Armin Krezović08368132016-09-30 14:11:05 +02006062 weston_compositor_add_pending_output(&output->base, b->compositor);
6063
Pekka Paalanend2e62422017-09-08 15:48:07 +03006064 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02006065}
6066
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006067static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03006068drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006069{
Pekka Paalanend2e62422017-09-08 15:48:07 +03006070 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006071 drmModeRes *resources;
6072 int i;
6073
Giulio Camuffo954f1832014-10-11 18:27:30 +03006074 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006075 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02006076 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006077 return -1;
6078 }
6079
Giulio Camuffo954f1832014-10-11 18:27:30 +03006080 b->min_width = resources->min_width;
6081 b->max_width = resources->max_width;
6082 b->min_height = resources->min_height;
6083 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05006084
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006085 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03006086 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00006087
Pekka Paalanend2e62422017-09-08 15:48:07 +03006088 head = drm_head_create(b, connector_id, drm_device);
6089 if (!head) {
6090 weston_log("DRM: failed to create head for connector %d.\n",
6091 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02006092 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006093 }
6094
Daniel Stone087ddf02017-02-14 17:51:30 +00006095 drm_backend_update_unused_outputs(b, resources);
6096
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006097 drmModeFreeResources(resources);
6098
6099 return 0;
6100}
6101
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006102static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03006103drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006104{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006105 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03006106 struct weston_head *base, *next;
6107 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006108 int i;
6109
Giulio Camuffo954f1832014-10-11 18:27:30 +03006110 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006111 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02006112 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006113 return;
6114 }
6115
Pekka Paalanend2e62422017-09-08 15:48:07 +03006116 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006117 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00006118 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02006119
Pekka Paalanend2e62422017-09-08 15:48:07 +03006120 head = drm_head_find_by_connector(b, connector_id);
6121 if (head) {
6122 drm_head_update_info(head);
6123 } else {
6124 head = drm_head_create(b, connector_id, drm_device);
6125 if (!head)
6126 weston_log("DRM: failed to create head for hot-added connector %d.\n",
6127 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01006128 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006129 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006130
Pekka Paalanend2e62422017-09-08 15:48:07 +03006131 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03006132 wl_list_for_each_safe(base, next,
6133 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03006134 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006135
Pekka Paalanena0a37462017-08-31 15:41:57 +03006136 head = to_drm_head(base);
6137
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006138 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03006139 if (resources->connectors[i] == head->connector_id) {
6140 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006141 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006142 }
6143 }
Armin Krezović08368132016-09-30 14:11:05 +02006144
Pekka Paalanend2e62422017-09-08 15:48:07 +03006145 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006146 continue;
6147
Pekka Paalanend2e62422017-09-08 15:48:07 +03006148 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
6149 head->base.name, head->connector_id);
6150 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006151 }
6152
Daniel Stone087ddf02017-02-14 17:51:30 +00006153 drm_backend_update_unused_outputs(b, resources);
6154
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006155 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006156}
6157
6158static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03006159udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006160{
David Herrmannd7488c22012-03-11 20:05:21 +01006161 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01006162 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01006163
6164 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006165 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01006166 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02006167
David Herrmann6ac52db2012-03-11 20:05:22 +01006168 val = udev_device_get_property_value(device, "HOTPLUG");
6169 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006170 return 0;
6171
David Herrmann6ac52db2012-03-11 20:05:22 +01006172 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006173}
6174
Kristian Høgsbergb1868472011-04-22 12:27:57 -04006175static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006176udev_drm_event(int fd, uint32_t mask, void *data)
6177{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006178 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006179 struct udev_device *event;
6180
Giulio Camuffo954f1832014-10-11 18:27:30 +03006181 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02006182
Giulio Camuffo954f1832014-10-11 18:27:30 +03006183 if (udev_event_is_hotplug(b, event))
Pekka Paalanend2e62422017-09-08 15:48:07 +03006184 drm_backend_update_heads(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006185
6186 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04006187
6188 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006189}
6190
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006191static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05006192drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006193{
Armin Krezović545dba62016-08-05 15:54:18 +02006194 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03006195 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006196
Giulio Camuffo954f1832014-10-11 18:27:30 +03006197 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02006198
Giulio Camuffo954f1832014-10-11 18:27:30 +03006199 wl_event_source_remove(b->udev_drm_source);
6200 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02006201
Daniel Stoneb57c6a02017-10-05 16:27:21 +01006202 b->shutting_down = true;
6203
Giulio Camuffo954f1832014-10-11 18:27:30 +03006204 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04006205
Marius Vlad7e4db952019-04-17 13:47:06 +03006206 weston_compositor_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01006207 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03006208 weston_compositor_shutdown(ec);
6209
Pekka Paalanenc112f002017-08-28 16:27:20 +03006210 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
6211 drm_head_destroy(to_drm_head(base));
6212
Giulio Camuffo954f1832014-10-11 18:27:30 +03006213 if (b->gbm)
6214 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006215
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02006216 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03006217 udev_unref(b->udev);
6218
Giulio Camuffo954f1832014-10-11 18:27:30 +03006219 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006220
Daniel Stone087ddf02017-02-14 17:51:30 +00006221 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00006222
Giulio Camuffo954f1832014-10-11 18:27:30 +03006223 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02006224 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006225 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006226}
6227
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006228static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006229session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006230{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006231 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02006232 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01006233 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006234 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006235
Giulio Camuffo954f1832014-10-11 18:27:30 +03006236 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006237 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00006238 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05006239 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00006240 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006241 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006242 } else {
6243 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03006244 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04006245
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01006246 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04006247
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006248 /* If we have a repaint scheduled (either from a
6249 * pending pageflip or the idle handler), make sure we
6250 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01006251 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05006252 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006253 * back, we schedule a repaint, which will process
6254 * pending frame callbacks. */
6255
Giulio Camuffo954f1832014-10-11 18:27:30 +03006256 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00006257 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01006258 if (output->cursor_plane)
6259 drmModeSetCursor(b->drm.fd, output->crtc_id,
6260 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006261 }
6262
Giulio Camuffo954f1832014-10-11 18:27:30 +03006263 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006264 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05006265
Daniel Stone085d2b92015-05-21 00:00:57 +01006266 wl_list_for_each(plane, &b->plane_list, link) {
6267 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
6268 continue;
6269
Giulio Camuffo954f1832014-10-11 18:27:30 +03006270 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01006271 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006272 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05006273 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01006274 }
6275 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006276}
6277
Robert Beckett8d23ab72019-06-13 16:55:44 +01006278
6279/**
6280 * Handle KMS GPU being added/removed
6281 *
6282 * If the device being added/removed is the KMS device, we activate/deactivate
6283 * the compositor session.
6284 *
6285 * @param compositor The compositor instance.
6286 * @param device The device being added/removed.
6287 * @param added Whether the device is being added (or removed)
6288 */
6289static void
6290drm_device_changed(struct weston_compositor *compositor,
6291 dev_t device, bool added)
6292{
6293 struct drm_backend *b = to_drm_backend(compositor);
6294
6295 if (b->drm.fd < 0 || b->drm.devnum != device)
6296 return;
6297
6298 compositor->session_active = added;
6299 wl_signal_emit(&compositor->session_signal, compositor);
6300}
6301
Daniel Stoneefa504f2016-12-19 16:48:20 +00006302/**
6303 * Determines whether or not a device is capable of modesetting. If successful,
6304 * sets b->drm.fd and b->drm.filename to the opened device.
6305 */
6306static bool
6307drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
6308{
6309 const char *filename = udev_device_get_devnode(device);
6310 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01006311 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006312 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02006313 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006314
6315 if (!filename)
6316 return false;
6317
6318 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
6319 if (fd < 0)
6320 return false;
6321
6322 res = drmModeGetResources(fd);
6323 if (!res)
6324 goto out_fd;
6325
6326 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
6327 res->count_encoders <= 0)
6328 goto out_res;
6329
6330 if (sysnum)
6331 id = atoi(sysnum);
6332 if (!sysnum || id < 0) {
6333 weston_log("couldn't get sysnum for device %s\n", filename);
6334 goto out_res;
6335 }
6336
6337 /* We can be called successfully on multiple devices; if we have,
6338 * clean up old entries. */
6339 if (b->drm.fd >= 0)
6340 weston_launcher_close(b->compositor->launcher, b->drm.fd);
6341 free(b->drm.filename);
6342
6343 b->drm.fd = fd;
6344 b->drm.id = id;
6345 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01006346 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006347
Sergi Granellceb59812017-03-28 12:44:04 +02006348 drmModeFreeResources(res);
6349
Daniel Stoneefa504f2016-12-19 16:48:20 +00006350 return true;
6351
6352out_res:
6353 drmModeFreeResources(res);
6354out_fd:
6355 weston_launcher_close(b->compositor->launcher, fd);
6356 return false;
6357}
6358
David Herrmann0af066f2012-10-29 19:21:16 +01006359/*
6360 * Find primary GPU
6361 * Some systems may have multiple DRM devices attached to a single seat. This
6362 * function loops over all devices and tries to find a PCI device with the
6363 * boot_vga sysfs attribute set to 1.
6364 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00006365 * Devices are also vetted to make sure they are are capable of modesetting,
6366 * rather than pure render nodes (GPU with no display), or pure
6367 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01006368 */
6369static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03006370find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01006371{
6372 struct udev_enumerate *e;
6373 struct udev_list_entry *entry;
6374 const char *path, *device_seat, *id;
6375 struct udev_device *device, *drm_device, *pci;
6376
Giulio Camuffo954f1832014-10-11 18:27:30 +03006377 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01006378 udev_enumerate_add_match_subsystem(e, "drm");
6379 udev_enumerate_add_match_sysname(e, "card[0-9]*");
6380
6381 udev_enumerate_scan_devices(e);
6382 drm_device = NULL;
6383 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00006384 bool is_boot_vga = false;
6385
David Herrmann0af066f2012-10-29 19:21:16 +01006386 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006387 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01006388 if (!device)
6389 continue;
6390 device_seat = udev_device_get_property_value(device, "ID_SEAT");
6391 if (!device_seat)
6392 device_seat = default_seat;
6393 if (strcmp(device_seat, seat)) {
6394 udev_device_unref(device);
6395 continue;
6396 }
6397
6398 pci = udev_device_get_parent_with_subsystem_devtype(device,
6399 "pci", NULL);
6400 if (pci) {
6401 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00006402 if (id && !strcmp(id, "1"))
6403 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01006404 }
6405
Daniel Stoneefa504f2016-12-19 16:48:20 +00006406 /* If we already have a modesetting-capable device, and this
6407 * device isn't our boot-VGA device, we aren't going to use
6408 * it. */
6409 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01006410 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006411 continue;
6412 }
6413
6414 /* Make sure this device is actually capable of modesetting;
6415 * if this call succeeds, b->drm.{fd,filename} will be set,
6416 * and any old values freed. */
6417 if (!drm_device_is_kms(b, device)) {
6418 udev_device_unref(device);
6419 continue;
6420 }
6421
6422 /* There can only be one boot_vga device, and we try to use it
6423 * at all costs. */
6424 if (is_boot_vga) {
6425 if (drm_device)
6426 udev_device_unref(drm_device);
6427 drm_device = device;
6428 break;
6429 }
6430
6431 /* Per the (!is_boot_vga && drm_device) test above, we only
6432 * trump existing saved devices with boot-VGA devices, so if
6433 * we end up here, this must be the first device we've seen. */
6434 assert(!drm_device);
6435 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01006436 }
6437
Daniel Stoneefa504f2016-12-19 16:48:20 +00006438 /* If we're returning a device to use, we must have an open FD for
6439 * it. */
6440 assert(!!drm_device == (b->drm.fd >= 0));
6441
David Herrmann0af066f2012-10-29 19:21:16 +01006442 udev_enumerate_unref(e);
6443 return drm_device;
6444}
6445
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006446static struct udev_device *
6447open_specific_drm_device(struct drm_backend *b, const char *name)
6448{
6449 struct udev_device *device;
6450
6451 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
6452 if (!device) {
6453 weston_log("ERROR: could not open DRM device '%s'\n", name);
6454 return NULL;
6455 }
6456
6457 if (!drm_device_is_kms(b, device)) {
6458 udev_device_unref(device);
6459 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
6460 return NULL;
6461 }
6462
6463 /* If we're returning a device to use, we must have an open FD for
6464 * it. */
6465 assert(b->drm.fd >= 0);
6466
6467 return device;
6468}
6469
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006470static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006471planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6472 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006473{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006474 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006475
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006476 switch (key) {
6477 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006478 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006479 break;
6480 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01006481 /* We don't support overlay-plane usage with legacy KMS. */
6482 if (b->atomic_modeset)
6483 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006484 break;
6485 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006486 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006487 break;
6488 default:
6489 break;
6490 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02006491}
6492
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07006493#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006494static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006495recorder_destroy(struct drm_output *output)
6496{
6497 vaapi_recorder_destroy(output->recorder);
6498 output->recorder = NULL;
6499
6500 output->base.disable_planes--;
6501
6502 wl_list_remove(&output->recorder_frame_listener.link);
6503 weston_log("[libva recorder] done\n");
6504}
6505
6506static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006507recorder_frame_notify(struct wl_listener *listener, void *data)
6508{
6509 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006510 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006511 int fd, ret;
6512
6513 output = container_of(listener, struct drm_output,
6514 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02006515 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006516
6517 if (!output->recorder)
6518 return;
6519
Daniel Stonee2e80132018-01-16 15:37:33 +00006520 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00006521 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006522 DRM_CLOEXEC, &fd);
6523 if (ret) {
6524 weston_log("[libva recorder] "
6525 "failed to create prime fd for front buffer\n");
6526 return;
6527 }
6528
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006529 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00006530 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006531 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02006532 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006533 recorder_destroy(output);
6534 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006535}
6536
6537static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03006538create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006539 const char *filename)
6540{
6541 int fd;
6542 drm_magic_t magic;
6543
Giulio Camuffo954f1832014-10-11 18:27:30 +03006544 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006545 if (fd < 0)
6546 return NULL;
6547
6548 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006549 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006550
6551 return vaapi_recorder_create(fd, width, height, filename);
6552}
6553
6554static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006555recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6556 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006557{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006558 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006559 struct drm_output *output;
6560 int width, height;
6561
Giulio Camuffo954f1832014-10-11 18:27:30 +03006562 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006563 struct drm_output, base.link);
6564
6565 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01006566 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03006567 weston_log("failed to start vaapi recorder: "
6568 "output format not supported\n");
6569 return;
6570 }
6571
Hardeningff39efa2013-09-18 23:56:35 +02006572 width = output->base.current_mode->width;
6573 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006574
6575 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03006576 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006577 if (!output->recorder) {
6578 weston_log("failed to create vaapi recorder\n");
6579 return;
6580 }
6581
6582 output->base.disable_planes++;
6583
6584 output->recorder_frame_listener.notify = recorder_frame_notify;
6585 wl_signal_add(&output->base.frame_signal,
6586 &output->recorder_frame_listener);
6587
6588 weston_output_schedule_repaint(&output->base);
6589
6590 weston_log("[libva recorder] initialized\n");
6591 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006592 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006593 }
6594}
6595#else
6596static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006597recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6598 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006599{
6600 weston_log("Compiled without libva support\n");
6601}
6602#endif
6603
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006604static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03006605switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006606{
6607 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006608 bool dmabuf_support_inited;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03006609 bool linux_explicit_sync_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006610
Giulio Camuffo954f1832014-10-11 18:27:30 +03006611 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006612 return;
6613
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006614 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03006615 linux_explicit_sync_inited =
6616 b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006617
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006618 weston_log("Switching to GL renderer\n");
6619
Giulio Camuffo954f1832014-10-11 18:27:30 +03006620 b->gbm = create_gbm_device(b->drm.fd);
6621 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006622 weston_log("Failed to create gbm device. "
6623 "Aborting renderer switch\n");
6624 return;
6625 }
6626
Giulio Camuffo954f1832014-10-11 18:27:30 +03006627 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006628 pixman_renderer_output_destroy(&output->base);
6629
Giulio Camuffo954f1832014-10-11 18:27:30 +03006630 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006631
Giulio Camuffo954f1832014-10-11 18:27:30 +03006632 if (drm_backend_create_gl_renderer(b) < 0) {
6633 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006634 weston_log("Failed to create GL renderer. Quitting.\n");
6635 /* FIXME: we need a function to shutdown cleanly */
6636 assert(0);
6637 }
6638
Giulio Camuffo954f1832014-10-11 18:27:30 +03006639 wl_list_for_each(output, &b->compositor->output_list, base.link)
6640 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006641
Giulio Camuffo954f1832014-10-11 18:27:30 +03006642 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006643
6644 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
6645 if (linux_dmabuf_setup(b->compositor) < 0)
6646 weston_log("Error: initializing dmabuf "
6647 "support failed.\n");
6648 }
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03006649
6650 if (!linux_explicit_sync_inited &&
6651 (b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC)) {
6652 if (linux_explicit_synchronization_setup(b->compositor) < 0)
6653 weston_log("Error: initializing explicit "
6654 " synchronization support failed.\n");
6655 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006656}
6657
6658static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006659renderer_switch_binding(struct weston_keyboard *keyboard,
6660 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006661{
Derek Foreman8ae2db52015-07-15 13:00:36 -05006662 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02006663 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006664
Giulio Camuffo954f1832014-10-11 18:27:30 +03006665 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006666}
6667
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09006668static void
6669drm_virtual_output_start_repaint_loop(struct weston_output *output_base)
6670{
6671 weston_output_finish_frame(output_base, NULL,
6672 WP_PRESENTATION_FEEDBACK_INVALID);
6673}
6674
6675static int
6676drm_virtual_output_submit_frame(struct drm_output *output,
6677 struct drm_fb *fb)
6678{
6679 struct drm_backend *b = to_drm_backend(output->base.compositor);
6680 int fd, ret;
6681
6682 assert(fb->num_planes == 1);
6683 ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd);
6684 if (ret) {
6685 weston_log("drmPrimeHandleFD failed, errno=%d\n", errno);
6686 return -1;
6687 }
6688
6689 drm_fb_ref(fb);
6690 ret = output->virtual_submit_frame(&output->base, fd, fb->strides[0],
6691 fb);
6692 if (ret < 0) {
6693 drm_fb_unref(fb);
6694 close(fd);
6695 }
6696 return ret;
6697}
6698
6699static int
6700drm_virtual_output_repaint(struct weston_output *output_base,
6701 pixman_region32_t *damage,
6702 void *repaint_data)
6703{
6704 struct drm_pending_state *pending_state = repaint_data;
6705 struct drm_output_state *state = NULL;
6706 struct drm_output *output = to_drm_output(output_base);
6707 struct drm_plane *scanout_plane = output->scanout_plane;
6708 struct drm_plane_state *scanout_state;
6709
6710 assert(output->virtual);
6711
6712 if (output->disable_pending || output->destroy_pending)
6713 goto err;
6714
6715 /* Drop frame if there isn't free buffers */
6716 if (!gbm_surface_has_free_buffers(output->gbm_surface)) {
6717 weston_log("%s: Drop frame!!\n", __func__);
6718 return -1;
6719 }
6720
6721 assert(!output->state_last);
6722
6723 /* If planes have been disabled in the core, we might not have
6724 * hit assign_planes at all, so might not have valid output state
6725 * here. */
6726 state = drm_pending_state_get_output(pending_state, output);
6727 if (!state)
6728 state = drm_output_state_duplicate(output->state_cur,
6729 pending_state,
6730 DRM_OUTPUT_STATE_CLEAR_PLANES);
6731
6732 drm_output_render(state, damage);
6733 scanout_state = drm_output_state_get_plane(state, scanout_plane);
6734 if (!scanout_state || !scanout_state->fb)
6735 goto err;
6736
6737 if (drm_virtual_output_submit_frame(output, scanout_state->fb) < 0)
6738 goto err;
6739
6740 return 0;
6741
6742err:
6743 drm_output_state_free(state);
6744 return -1;
6745}
6746
6747static void
6748drm_virtual_output_deinit(struct weston_output *base)
6749{
6750 struct drm_output *output = to_drm_output(base);
6751
6752 drm_output_fini_egl(output);
6753
6754 drm_virtual_plane_destroy(output->scanout_plane);
6755}
6756
6757static void
6758drm_virtual_output_destroy(struct weston_output *base)
6759{
6760 struct drm_output *output = to_drm_output(base);
6761
6762 assert(output->virtual);
6763
6764 if (output->base.enabled)
6765 drm_virtual_output_deinit(&output->base);
6766
6767 weston_output_release(&output->base);
6768
6769 drm_output_state_free(output->state_cur);
6770
6771 free(output);
6772}
6773
6774static int
6775drm_virtual_output_enable(struct weston_output *output_base)
6776{
6777 struct drm_output *output = to_drm_output(output_base);
6778 struct drm_backend *b = to_drm_backend(output_base->compositor);
6779
6780 assert(output->virtual);
6781
6782 if (b->use_pixman) {
6783 weston_log("Not support pixman renderer on Virtual output\n");
6784 goto err;
6785 }
6786
6787 if (!output->virtual_submit_frame) {
6788 weston_log("The virtual_submit_frame hook is not set\n");
6789 goto err;
6790 }
6791
6792 output->scanout_plane = drm_virtual_plane_create(b, output);
6793 if (!output->scanout_plane) {
6794 weston_log("Failed to find primary plane for output %s\n",
6795 output->base.name);
6796 return -1;
6797 }
6798
6799 if (drm_output_init_egl(output, b) < 0) {
6800 weston_log("Failed to init output gl state\n");
6801 goto err;
6802 }
6803
6804 output->base.start_repaint_loop = drm_virtual_output_start_repaint_loop;
6805 output->base.repaint = drm_virtual_output_repaint;
6806 output->base.assign_planes = drm_assign_planes;
6807 output->base.set_dpms = NULL;
6808 output->base.switch_mode = NULL;
6809 output->base.gamma_size = 0;
6810 output->base.set_gamma = NULL;
6811
6812 weston_compositor_stack_plane(b->compositor,
6813 &output->scanout_plane->base,
6814 &b->compositor->primary_plane);
6815
6816 return 0;
6817err:
6818 return -1;
6819}
6820
6821static int
6822drm_virtual_output_disable(struct weston_output *base)
6823{
6824 struct drm_output *output = to_drm_output(base);
6825
6826 assert(output->virtual);
6827
6828 if (output->base.enabled)
6829 drm_virtual_output_deinit(&output->base);
6830
6831 return 0;
6832}
6833
6834static struct weston_output *
6835drm_virtual_output_create(struct weston_compositor *c, char *name)
6836{
6837 struct drm_output *output;
6838
6839 output = zalloc(sizeof *output);
6840 if (!output)
6841 return NULL;
6842
6843 output->virtual = true;
6844 output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
6845
6846 weston_output_init(&output->base, c, name);
6847
6848 output->base.enable = drm_virtual_output_enable;
6849 output->base.destroy = drm_virtual_output_destroy;
6850 output->base.disable = drm_virtual_output_disable;
6851 output->base.attach_head = NULL;
6852
6853 output->state_cur = drm_output_state_alloc(output, NULL);
6854
6855 weston_compositor_add_pending_output(&output->base, c);
6856
6857 return &output->base;
6858}
6859
6860static uint32_t
6861drm_virtual_output_set_gbm_format(struct weston_output *base,
6862 const char *gbm_format)
6863{
6864 struct drm_output *output = to_drm_output(base);
6865 struct drm_backend *b = to_drm_backend(base->compositor);
6866
6867 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
6868 output->gbm_format = b->gbm_format;
6869
6870 return output->gbm_format;
6871}
6872
6873static void
6874drm_virtual_output_set_submit_frame_cb(struct weston_output *output_base,
6875 submit_frame_cb cb)
6876{
6877 struct drm_output *output = to_drm_output(output_base);
6878
6879 output->virtual_submit_frame = cb;
6880}
6881
6882static int
6883drm_virtual_output_get_fence_fd(struct weston_output *output_base)
6884{
6885 return gl_renderer->create_fence_fd(output_base);
6886}
6887
6888static void
6889drm_virtual_output_buffer_released(struct drm_fb *fb)
6890{
6891 drm_fb_unref(fb);
6892}
6893
6894static void
6895drm_virtual_output_finish_frame(struct weston_output *output_base,
6896 struct timespec *stamp,
6897 uint32_t presented_flags)
6898{
6899 struct drm_output *output = to_drm_output(output_base);
6900 struct drm_plane_state *ps;
6901
6902 wl_list_for_each(ps, &output->state_cur->plane_list, link)
6903 ps->complete = true;
6904
6905 drm_output_state_free(output->state_last);
6906 output->state_last = NULL;
6907
6908 weston_output_finish_frame(&output->base, stamp, presented_flags);
6909
6910 /* We can't call this from frame_notify, because the output's
6911 * repaint needed flag is cleared just after that */
6912 if (output->recorder)
6913 weston_output_schedule_repaint(&output->base);
6914}
6915
Armin Krezović08368132016-09-30 14:11:05 +02006916static const struct weston_drm_output_api api = {
6917 drm_output_set_mode,
6918 drm_output_set_gbm_format,
6919 drm_output_set_seat,
6920};
6921
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09006922static const struct weston_drm_virtual_output_api virt_api = {
6923 drm_virtual_output_create,
6924 drm_virtual_output_set_gbm_format,
6925 drm_virtual_output_set_submit_frame_cb,
6926 drm_virtual_output_get_fence_fd,
6927 drm_virtual_output_buffer_released,
6928 drm_virtual_output_finish_frame
6929};
6930
Giulio Camuffo954f1832014-10-11 18:27:30 +03006931static struct drm_backend *
6932drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006933 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006934{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006935 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01006936 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006937 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006938 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04006939 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02006940 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006941
nerdopolisb16c4ac2018-06-29 08:17:46 -04006942 session_seat = getenv("XDG_SEAT");
6943 if (session_seat)
6944 seat_id = session_seat;
6945
6946 if (config->seat_id)
6947 seat_id = config->seat_id;
6948
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04006949 weston_log("initializing drm backend\n");
6950
Giulio Camuffo954f1832014-10-11 18:27:30 +03006951 b = zalloc(sizeof *b);
6952 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006953 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01006954
Daniel Stone6020f472018-02-05 15:46:20 +00006955 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006956 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00006957 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006958
Giulio Camuffo954f1832014-10-11 18:27:30 +03006959 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006960 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00006961 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02006962 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006963
Marius Vlad7e4db952019-04-17 13:47:06 +03006964 b->debug = weston_compositor_add_log_scope(compositor->weston_log_ctx,
6965 "drm-backend",
6966 "Debug messages from DRM/KMS backend\n",
6967 NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01006968
Pekka Paalanen7da9a382017-08-30 11:29:49 +03006969 compositor->backend = &b->base;
6970
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006971 if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
6972 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006973
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006974 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006975 compositor->launcher = weston_launcher_connect(compositor, config->tty,
6976 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006977 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02006978 weston_log("fatal: drm backend should be run using "
6979 "weston-launch binary, or your system should "
6980 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006981 goto err_compositor;
6982 }
6983
Giulio Camuffo954f1832014-10-11 18:27:30 +03006984 b->udev = udev_new();
6985 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006986 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006987 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006988 }
6989
Giulio Camuffo954f1832014-10-11 18:27:30 +03006990 b->session_listener.notify = session_notify;
6991 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05006992
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006993 if (config->specific_device)
6994 drm_device = open_specific_drm_device(b, config->specific_device);
6995 else
6996 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04006997 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006998 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006999 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007000 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007001
Daniel Stoneefa504f2016-12-19 16:48:20 +00007002 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02007003 weston_log("failed to initialize kms\n");
7004 goto err_udev_dev;
7005 }
7006
Giulio Camuffo954f1832014-10-11 18:27:30 +03007007 if (b->use_pixman) {
7008 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02007009 weston_log("failed to initialize pixman renderer\n");
7010 goto err_udev_dev;
7011 }
7012 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03007013 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02007014 weston_log("failed to initialize egl\n");
7015 goto err_udev_dev;
7016 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007017 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05007018
Giulio Camuffo954f1832014-10-11 18:27:30 +03007019 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00007020 b->base.repaint_begin = drm_repaint_begin;
7021 b->base.repaint_flush = drm_repaint_flush;
7022 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03007023 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01007024 b->base.device_changed = drm_device_changed;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02007025
Bob Ham91880f12016-01-12 10:21:47 +00007026 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04007027
Daniel Stone085d2b92015-05-21 00:00:57 +01007028 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007029 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05007030
Giulio Camuffo954f1832014-10-11 18:27:30 +03007031 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03007032 compositor, b->udev, seat_id,
7033 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03007034 weston_log("failed to create input devices\n");
7035 goto err_sprite;
7036 }
7037
Pekka Paalanend2e62422017-09-08 15:48:07 +03007038 if (drm_backend_create_heads(b, drm_device) < 0) {
7039 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03007040 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007041 }
7042
Jason Ekstrand9fc71512014-04-02 19:53:46 -05007043 /* A this point we have some idea of whether or not we have a working
7044 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03007045 if (!b->cursors_are_broken)
7046 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05007047
Giulio Camuffo954f1832014-10-11 18:27:30 +03007048 loop = wl_display_get_event_loop(compositor->wl_display);
7049 b->drm_source =
7050 wl_event_loop_add_fd(loop, b->drm.fd,
7051 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007052
Giulio Camuffo954f1832014-10-11 18:27:30 +03007053 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
7054 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05007055 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01007056 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01007057 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03007058 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01007059 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007060 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02007061 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03007062 udev_monitor_get_fd(b->udev_monitor),
7063 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01007064
Giulio Camuffo954f1832014-10-11 18:27:30 +03007065 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02007066 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01007067 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01007068 }
7069
Daniel Stonea96b93c2012-06-22 14:04:37 +01007070 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007071
Giulio Camuffo954f1832014-10-11 18:27:30 +03007072 weston_compositor_add_debug_binding(compositor, KEY_O,
7073 planes_binding, b);
7074 weston_compositor_add_debug_binding(compositor, KEY_C,
7075 planes_binding, b);
7076 weston_compositor_add_debug_binding(compositor, KEY_V,
7077 planes_binding, b);
7078 weston_compositor_add_debug_binding(compositor, KEY_Q,
7079 recorder_binding, b);
7080 weston_compositor_add_debug_binding(compositor, KEY_W,
7081 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02007082
Pekka Paalanene4d231e2014-06-12 15:12:48 +03007083 if (compositor->renderer->import_dmabuf) {
7084 if (linux_dmabuf_setup(compositor) < 0)
7085 weston_log("Error: initializing dmabuf "
7086 "support failed.\n");
7087 }
7088
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03007089 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
7090 if (linux_explicit_synchronization_setup(compositor) < 0)
7091 weston_log("Error: initializing explicit "
7092 " synchronization support failed.\n");
7093 }
7094
Armin Krezović08368132016-09-30 14:11:05 +02007095 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
7096 &api, sizeof(api));
7097
7098 if (ret < 0) {
7099 weston_log("Failed to register output API.\n");
7100 goto err_udev_monitor;
7101 }
7102
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09007103 ret = weston_plugin_api_register(compositor,
7104 WESTON_DRM_VIRTUAL_OUTPUT_API_NAME,
7105 &virt_api, sizeof(virt_api));
7106 if (ret < 0) {
7107 weston_log("Failed to register virtual output API.\n");
7108 goto err_udev_monitor;
7109 }
7110
Giulio Camuffo954f1832014-10-11 18:27:30 +03007111 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01007112
7113err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007114 wl_event_source_remove(b->udev_drm_source);
7115 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007116err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007117 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03007118err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007119 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04007120err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01007121 if (b->gbm)
7122 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007123 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007124err_udev_dev:
7125 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07007126err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007127 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007128err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007129 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007130err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007131 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007132 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007133 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007134}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007135
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007136static void
7137config_init_to_defaults(struct weston_drm_backend_config *config)
7138{
Pekka Paalanendee412d2018-04-23 11:44:58 +02007139 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007140}
7141
Giulio Camuffo954f1832014-10-11 18:27:30 +03007142WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01007143weston_backend_init(struct weston_compositor *compositor,
7144 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007145{
Giulio Camuffo954f1832014-10-11 18:27:30 +03007146 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007147 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007148
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007149 if (config_base == NULL ||
7150 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
7151 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
7152 weston_log("drm backend config structure is invalid\n");
7153 return -1;
7154 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02007155
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007156 config_init_to_defaults(&config);
7157 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07007158
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007159 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007160 if (b == NULL)
7161 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007162
Giulio Camuffo954f1832014-10-11 18:27:30 +03007163 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007164}