blob: 3d777d4b56033de08ee33d155ab3d70047da01dc [file] [log] [blame]
Daniel Stone4c2fc702019-06-18 11:12:07 +01001/*
2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
4 * Copyright © 2017, 2018 Collabora, Ltd.
5 * Copyright © 2017, 2018 General Electric Company
6 * Copyright (c) 2018 DisplayLink (UK) Ltd.
7 *
8 * 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:
15 *
16 * 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.
28 */
29
30#include "config.h"
31
32#include <stdint.h>
33
34#include <xf86drm.h>
35#include <xf86drmMode.h>
Daniel Stone4c2fc702019-06-18 11:12:07 +010036
Daniel Stone4c2fc702019-06-18 11:12:07 +010037#include <libweston/libweston.h>
38#include <libweston/backend-drm.h>
39#include "shared/helpers.h"
Pekka Paalanen4b301fe2021-02-04 17:39:45 +020040#include "shared/weston-drm-fourcc.h"
Daniel Stone4c2fc702019-06-18 11:12:07 +010041#include "drm-internal.h"
42#include "pixel-formats.h"
43#include "presentation-time-server-protocol.h"
44
leng.fang32af9fc2024-06-13 11:22:15 +080045#include "aml-weston/aml-backend.h"
46
Daniel Stone4c2fc702019-06-18 11:12:07 +010047struct drm_property_enum_info plane_type_enums[] = {
48 [WDRM_PLANE_TYPE_PRIMARY] = {
49 .name = "Primary",
50 },
51 [WDRM_PLANE_TYPE_OVERLAY] = {
52 .name = "Overlay",
53 },
54 [WDRM_PLANE_TYPE_CURSOR] = {
55 .name = "Cursor",
56 },
57};
58
59const struct drm_property_info plane_props[] = {
60 [WDRM_PLANE_TYPE] = {
61 .name = "type",
62 .enum_values = plane_type_enums,
63 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
64 },
65 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
66 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
67 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
68 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
69 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
70 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
71 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
72 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
73 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
74 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
75 [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" },
76 [WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
77 [WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
Marius Vladcdd6fa22019-08-29 20:42:00 +030078 [WDRM_PLANE_ZPOS] = { .name = "zpos" },
Daniel Stone4c2fc702019-06-18 11:12:07 +010079};
80
81struct drm_property_enum_info dpms_state_enums[] = {
82 [WDRM_DPMS_STATE_OFF] = {
83 .name = "Off",
84 },
85 [WDRM_DPMS_STATE_ON] = {
86 .name = "On",
87 },
88 [WDRM_DPMS_STATE_STANDBY] = {
89 .name = "Standby",
90 },
91 [WDRM_DPMS_STATE_SUSPEND] = {
92 .name = "Suspend",
93 },
94};
95
Ankit Nautiyala344fe32019-05-14 18:36:08 +053096struct drm_property_enum_info content_protection_enums[] = {
97 [WDRM_CONTENT_PROTECTION_UNDESIRED] = {
98 .name = "Undesired",
99 },
100 [WDRM_CONTENT_PROTECTION_DESIRED] = {
101 .name = "Desired",
102 },
103 [WDRM_CONTENT_PROTECTION_ENABLED] = {
104 .name = "Enabled",
105 },
106};
107
108struct drm_property_enum_info hdcp_content_type_enums[] = {
109 [WDRM_HDCP_CONTENT_TYPE0] = {
110 .name = "HDCP Type0",
111 },
112 [WDRM_HDCP_CONTENT_TYPE1] = {
113 .name = "HDCP Type1",
114 },
115};
116
Lucas Stach72e7a1e2019-11-25 23:31:57 +0000117struct drm_property_enum_info panel_orientation_enums[] = {
118 [WDRM_PANEL_ORIENTATION_NORMAL] = { .name = "Normal", },
119 [WDRM_PANEL_ORIENTATION_UPSIDE_DOWN] = { .name = "Upside Down", },
120 [WDRM_PANEL_ORIENTATION_LEFT_SIDE_UP] = { .name = "Left Side Up", },
121 [WDRM_PANEL_ORIENTATION_RIGHT_SIDE_UP] = { .name = "Right Side Up", },
122};
123
Daniel Stone4c2fc702019-06-18 11:12:07 +0100124const struct drm_property_info connector_props[] = {
125 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
126 [WDRM_CONNECTOR_DPMS] = {
127 .name = "DPMS",
128 .enum_values = dpms_state_enums,
129 .num_enum_values = WDRM_DPMS_STATE__COUNT,
130 },
131 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
132 [WDRM_CONNECTOR_NON_DESKTOP] = { .name = "non-desktop", },
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530133 [WDRM_CONNECTOR_CONTENT_PROTECTION] = {
leng.fangdbaf6fa2024-06-20 19:31:04 +0800134 .name = "ContentProtection",
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530135 .enum_values = content_protection_enums,
136 .num_enum_values = WDRM_CONTENT_PROTECTION__COUNT,
137 },
138 [WDRM_CONNECTOR_HDCP_CONTENT_TYPE] = {
139 .name = "HDCP Content Type",
140 .enum_values = hdcp_content_type_enums,
141 .num_enum_values = WDRM_HDCP_CONTENT_TYPE__COUNT,
142 },
Lucas Stach72e7a1e2019-11-25 23:31:57 +0000143 [WDRM_CONNECTOR_PANEL_ORIENTATION] = {
144 .name = "panel orientation",
145 .enum_values = panel_orientation_enums,
146 .num_enum_values = WDRM_PANEL_ORIENTATION__COUNT,
147 },
Daniel Stone4c2fc702019-06-18 11:12:07 +0100148};
149
150const struct drm_property_info crtc_props[] = {
151 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
152 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
153};
154
155
156/**
157 * Mode for drm_pending_state_apply and co.
158 */
159enum drm_state_apply_mode {
160 DRM_STATE_APPLY_SYNC, /**< state fully processed */
161 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
162 DRM_STATE_TEST_ONLY, /**< test if the state can be applied */
163};
164
165/**
166 * Get the current value of a KMS property
167 *
168 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
169 * for the target property, return the current value of that property,
170 * with an optional default. If the property is a KMS enum type, the return
171 * value will be translated into the appropriate internal enum.
172 *
173 * If the property is not present, the default value will be returned.
174 *
175 * @param info Internal structure for property to look up
176 * @param props Raw KMS properties for the target object
177 * @param def Value to return if property is not found
178 */
179uint64_t
180drm_property_get_value(struct drm_property_info *info,
181 const drmModeObjectProperties *props,
182 uint64_t def)
183{
184 unsigned int i;
185
186 if (info->prop_id == 0)
187 return def;
188
189 for (i = 0; i < props->count_props; i++) {
190 unsigned int j;
191
192 if (props->props[i] != info->prop_id)
193 continue;
194
195 /* Simple (non-enum) types can return the value directly */
196 if (info->num_enum_values == 0)
197 return props->prop_values[i];
198
199 /* Map from raw value to enum value */
200 for (j = 0; j < info->num_enum_values; j++) {
201 if (!info->enum_values[j].valid)
202 continue;
203 if (info->enum_values[j].value != props->prop_values[i])
204 continue;
205
206 return j;
207 }
208
209 /* We don't have a mapping for this enum; return default. */
210 break;
211 }
212
213 return def;
214}
215
216/**
Marius Vlad1accffe2019-11-01 12:00:09 +0200217 * Get the current range values of a KMS property
218 *
219 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
220 * for the target property, return the current range values of that property,
221 *
222 * If the property is not present, or there's no it is not a prop range then
223 * NULL will be returned.
224 *
225 * @param info Internal structure for property to look up
226 * @param props Raw KMS properties for the target object
227 */
228uint64_t *
229drm_property_get_range_values(struct drm_property_info *info,
230 const drmModeObjectProperties *props)
231{
232 unsigned int i;
233
234 if (info->prop_id == 0)
235 return NULL;
236
237 for (i = 0; i < props->count_props; i++) {
238
239 if (props->props[i] != info->prop_id)
240 continue;
241
242 if (!(info->flags & DRM_MODE_PROP_RANGE) &&
243 !(info->flags & DRM_MODE_PROP_SIGNED_RANGE))
244 continue;
245
246 return info->range_values;
247 }
248
249 return NULL;
250}
251
252/**
Daniel Stone4c2fc702019-06-18 11:12:07 +0100253 * Cache DRM property values
254 *
255 * Update a per-object array of drm_property_info structures, given the
256 * DRM properties of the object.
257 *
258 * Call this every time an object newly appears (note that only connectors
259 * can be hotplugged), the first time it is seen, or when its status changes
260 * in a way which invalidates the potential property values (currently, the
261 * only case for this is connector hotplug).
262 *
263 * This updates the property IDs and enum values within the drm_property_info
264 * array.
265 *
266 * DRM property enum values are dynamic at runtime; the user must query the
267 * property to find out the desired runtime value for a requested string
268 * name. Using the 'type' field on planes as an example, there is no single
269 * hardcoded constant for primary plane types; instead, the property must be
270 * queried at runtime to find the value associated with the string "Primary".
271 *
272 * This helper queries and caches the enum values, to allow us to use a set
273 * of compile-time-constant enums portably across various implementations.
274 * The values given in enum_names are searched for, and stored in the
275 * same-indexed field of the map array.
276 *
277 * @param b DRM backend object
278 * @param src DRM property info array to source from
279 * @param info DRM property info array to copy into
280 * @param num_infos Number of entries in the source array
281 * @param props DRM object properties for the object
282 */
283void
284drm_property_info_populate(struct drm_backend *b,
285 const struct drm_property_info *src,
286 struct drm_property_info *info,
287 unsigned int num_infos,
288 drmModeObjectProperties *props)
289{
290 drmModePropertyRes *prop;
291 unsigned i, j;
292
293 for (i = 0; i < num_infos; i++) {
294 unsigned int j;
295
296 info[i].name = src[i].name;
297 info[i].prop_id = 0;
298 info[i].num_enum_values = src[i].num_enum_values;
299
300 if (src[i].num_enum_values == 0)
301 continue;
302
303 info[i].enum_values =
304 malloc(src[i].num_enum_values *
305 sizeof(*info[i].enum_values));
306 assert(info[i].enum_values);
307 for (j = 0; j < info[i].num_enum_values; j++) {
308 info[i].enum_values[j].name = src[i].enum_values[j].name;
309 info[i].enum_values[j].valid = false;
310 }
311 }
312
313 for (i = 0; i < props->count_props; i++) {
314 unsigned int k;
315
316 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
317 if (!prop)
318 continue;
319
320 for (j = 0; j < num_infos; j++) {
321 if (!strcmp(prop->name, info[j].name))
322 break;
323 }
324
325 /* We don't know/care about this property. */
326 if (j == num_infos) {
327#ifdef DEBUG
328 weston_log("DRM debug: unrecognized property %u '%s'\n",
329 prop->prop_id, prop->name);
330#endif
331 drmModeFreeProperty(prop);
332 continue;
333 }
334
335 if (info[j].num_enum_values == 0 &&
336 (prop->flags & DRM_MODE_PROP_ENUM)) {
337 weston_log("DRM: expected property %s to not be an"
338 " enum, but it is; ignoring\n", prop->name);
339 drmModeFreeProperty(prop);
340 continue;
341 }
342
343 info[j].prop_id = props->props[i];
Marius Vlad1accffe2019-11-01 12:00:09 +0200344 info[j].flags = prop->flags;
345
346 if (prop->flags & DRM_MODE_PROP_RANGE ||
347 prop->flags & DRM_MODE_PROP_SIGNED_RANGE) {
348 info[j].num_range_values = prop->count_values;
349 for (int i = 0; i < prop->count_values; i++)
350 info[j].range_values[i] = prop->values[i];
351 }
352
Daniel Stone4c2fc702019-06-18 11:12:07 +0100353
354 if (info[j].num_enum_values == 0) {
355 drmModeFreeProperty(prop);
356 continue;
357 }
358
359 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
360 weston_log("DRM: expected property %s to be an enum,"
361 " but it is not; ignoring\n", prop->name);
362 drmModeFreeProperty(prop);
363 info[j].prop_id = 0;
364 continue;
365 }
366
367 for (k = 0; k < info[j].num_enum_values; k++) {
368 int l;
369
370 for (l = 0; l < prop->count_enums; l++) {
371 if (!strcmp(prop->enums[l].name,
372 info[j].enum_values[k].name))
373 break;
374 }
375
376 if (l == prop->count_enums)
377 continue;
378
379 info[j].enum_values[k].valid = true;
380 info[j].enum_values[k].value = prop->enums[l].value;
381 }
382
383 drmModeFreeProperty(prop);
384 }
385
386#ifdef DEBUG
387 for (i = 0; i < num_infos; i++) {
388 if (info[i].prop_id == 0)
389 weston_log("DRM warning: property '%s' missing\n",
390 info[i].name);
391 }
392#endif
393}
394
395/**
396 * Free DRM property information
397 *
398 * Frees all memory associated with a DRM property info array and zeroes
399 * it out, leaving it usable for a further drm_property_info_update() or
400 * drm_property_info_free().
401 *
402 * @param info DRM property info array
403 * @param num_props Number of entries in array to free
404 */
405void
406drm_property_info_free(struct drm_property_info *info, int num_props)
407{
408 int i;
409
410 for (i = 0; i < num_props; i++)
411 free(info[i].enum_values);
412
413 memset(info, 0, sizeof(*info) * num_props);
414}
415
Daniel Stone4c2fc702019-06-18 11:12:07 +0100416static inline uint32_t *
417formats_ptr(struct drm_format_modifier_blob *blob)
418{
419 return (uint32_t *)(((char *)blob) + blob->formats_offset);
420}
421
422static inline struct drm_format_modifier *
423modifiers_ptr(struct drm_format_modifier_blob *blob)
424{
425 return (struct drm_format_modifier *)
426 (((char *)blob) + blob->modifiers_offset);
427}
Daniel Stone4c2fc702019-06-18 11:12:07 +0100428
429/**
430 * Populates the plane's formats array, using either the IN_FORMATS blob
431 * property (if available), or the plane's format list if not.
432 */
433int
434drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
Stefan Agner465ab2c2020-06-17 23:36:44 +0200435 const drmModeObjectProperties *props,
436 const bool use_modifiers)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100437{
Scott Anderson74663092021-02-01 15:46:33 -0300438 unsigned i, j;
439 drmModePropertyBlobRes *blob = NULL;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100440 struct drm_format_modifier_blob *fmt_mod_blob;
441 struct drm_format_modifier *blob_modifiers;
442 uint32_t *blob_formats;
443 uint32_t blob_id;
Scott Anderson74663092021-02-01 15:46:33 -0300444 struct weston_drm_format *fmt;
445 int ret = 0;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100446
Stefan Agner465ab2c2020-06-17 23:36:44 +0200447 if (!use_modifiers)
448 goto fallback;
449
Daniel Stone4c2fc702019-06-18 11:12:07 +0100450 blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
451 props,
452 0);
453 if (blob_id == 0)
454 goto fallback;
455
456 blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
457 if (!blob)
458 goto fallback;
459
460 fmt_mod_blob = blob->data;
461 blob_formats = formats_ptr(fmt_mod_blob);
462 blob_modifiers = modifiers_ptr(fmt_mod_blob);
463
Scott Anderson74663092021-02-01 15:46:33 -0300464 assert(kplane->count_formats == fmt_mod_blob->count_formats);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100465
466 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
Scott Anderson74663092021-02-01 15:46:33 -0300467 fmt = weston_drm_format_array_add_format(&plane->formats,
468 blob_formats[i]);
469 if (!fmt) {
470 ret = -1;
471 goto out;
472 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100473
474 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
475 struct drm_format_modifier *mod = &blob_modifiers[j];
476
477 if ((i < mod->offset) || (i > mod->offset + 63))
478 continue;
479 if (!(mod->formats & (1 << (i - mod->offset))))
480 continue;
481
Scott Anderson74663092021-02-01 15:46:33 -0300482 ret = weston_drm_format_add_modifier(fmt, mod->modifier);
483 if (ret < 0)
484 goto out;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100485 }
486
Leandro Ribeiro98101e82021-04-21 11:46:35 -0300487 if (fmt->modifiers.size == 0)
488 weston_drm_format_array_remove_latest_format(&plane->formats);
leng.fang32af9fc2024-06-13 11:22:15 +0800489
490 if (fmt->format == DRM_FORMAT_NV12 ||
491 fmt->format == DRM_FORMAT_NV21)
492 plane->is_video_plane = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100493 }
494
Scott Anderson74663092021-02-01 15:46:33 -0300495out:
Daniel Stone4c2fc702019-06-18 11:12:07 +0100496 drmModeFreePropertyBlob(blob);
Scott Anderson74663092021-02-01 15:46:33 -0300497 return ret;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100498
499fallback:
Daniel Stone4c2fc702019-06-18 11:12:07 +0100500 /* No IN_FORMATS blob available, so just use the old. */
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900501 for (i = 0; i < kplane->count_formats; i++) {
Scott Anderson74663092021-02-01 15:46:33 -0300502 fmt = weston_drm_format_array_add_format(&plane->formats,
503 kplane->formats[i]);
504 if (!fmt)
505 return -1;
Leandro Ribeiro567cc922021-04-21 11:44:53 -0300506 ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_INVALID);
Scott Anderson74663092021-02-01 15:46:33 -0300507 if (ret < 0)
508 return -1;
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900509 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100510 return 0;
511}
512
513void
514drm_output_set_gamma(struct weston_output *output_base,
515 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
516{
517 int rc;
518 struct drm_output *output = to_drm_output(output_base);
519 struct drm_backend *backend =
520 to_drm_backend(output->base.compositor);
521
522 /* check */
523 if (output_base->gamma_size != size)
524 return;
525
526 rc = drmModeCrtcSetGamma(backend->drm.fd,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300527 output->crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100528 size, r, g, b);
529 if (rc)
530 weston_log("set gamma failed: %s\n", strerror(errno));
531}
532
533/**
534 * Mark an output state as current on the output, i.e. it has been
535 * submitted to the kernel. The mode argument determines whether this
536 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
537 * or asynchronously (in which case we wait for events to complete).
538 */
539static void
540drm_output_assign_state(struct drm_output_state *state,
541 enum drm_state_apply_mode mode)
542{
543 struct drm_output *output = state->output;
544 struct drm_backend *b = to_drm_backend(output->base.compositor);
545 struct drm_plane_state *plane_state;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530546 struct drm_head *head;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100547
548 assert(!output->state_last);
549
550 if (mode == DRM_STATE_APPLY_ASYNC)
551 output->state_last = output->state_cur;
552 else
553 drm_output_state_free(output->state_cur);
554
555 wl_list_remove(&state->link);
556 wl_list_init(&state->link);
557 state->pending_state = NULL;
558
559 output->state_cur = state;
560
561 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300562 drm_debug(b, "\t[CRTC:%u] setting pending flip\n",
563 output->crtc->crtc_id);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100564 output->atomic_complete_pending = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100565 }
566
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530567 if (b->atomic_modeset &&
568 state->protection == WESTON_HDCP_DISABLE)
569 wl_list_for_each(head, &output->base.head_list, base.output_link)
570 weston_head_set_content_protection_status(&head->base,
571 WESTON_HDCP_DISABLE);
572
Daniel Stone4c2fc702019-06-18 11:12:07 +0100573 /* Replace state_cur on each affected plane with the new state, being
574 * careful to dispose of orphaned (but only orphaned) previous state.
575 * If the previous state is not orphaned (still has an output_state
576 * attached), it will be disposed of by freeing the output_state. */
577 wl_list_for_each(plane_state, &state->plane_list, link) {
578 struct drm_plane *plane = plane_state->plane;
579
580 if (plane->state_cur && !plane->state_cur->output_state)
581 drm_plane_state_free(plane->state_cur, true);
582 plane->state_cur = plane_state;
583
584 if (mode != DRM_STATE_APPLY_ASYNC) {
585 plane_state->complete = true;
586 continue;
587 }
588
589 if (b->atomic_modeset)
590 continue;
591
592 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
593 if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100594 output->page_flip_pending = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100595 }
596}
597
598static void
599drm_output_set_cursor(struct drm_output_state *output_state)
600{
601 struct drm_output *output = output_state->output;
602 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300603 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100604 struct drm_plane *plane = output->cursor_plane;
605 struct drm_plane_state *state;
Stefan Agner974390a2019-07-08 00:42:05 +0200606 uint32_t handle;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100607
608 if (!plane)
609 return;
610
611 state = drm_output_state_get_existing_plane(output_state, plane);
612 if (!state)
613 return;
614
615 if (!state->fb) {
616 pixman_region32_fini(&plane->base.damage);
617 pixman_region32_init(&plane->base.damage);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300618 drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100619 return;
620 }
621
622 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
623 assert(!plane->state_cur->output || plane->state_cur->output == output);
624
Stefan Agner974390a2019-07-08 00:42:05 +0200625 handle = output->gbm_cursor_handle[output->current_cursor];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100626 if (plane->state_cur->fb != state->fb) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300627 if (drmModeSetCursor(b->drm.fd, crtc->crtc_id, handle,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100628 b->cursor_width, b->cursor_height)) {
629 weston_log("failed to set cursor: %s\n",
630 strerror(errno));
631 goto err;
632 }
633 }
634
635 pixman_region32_fini(&plane->base.damage);
636 pixman_region32_init(&plane->base.damage);
637
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300638 if (drmModeMoveCursor(b->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100639 state->dest_x, state->dest_y)) {
640 weston_log("failed to move cursor: %s\n", strerror(errno));
641 goto err;
642 }
643
644 return;
645
646err:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100647 b->cursors_are_broken = true;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300648 drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100649}
650
651static int
652drm_output_apply_state_legacy(struct drm_output_state *state)
653{
654 struct drm_output *output = state->output;
655 struct drm_backend *backend = to_drm_backend(output->base.compositor);
656 struct drm_plane *scanout_plane = output->scanout_plane;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300657 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100658 struct drm_property_info *dpms_prop;
659 struct drm_plane_state *scanout_state;
660 struct drm_mode *mode;
661 struct drm_head *head;
662 const struct pixel_format_info *pinfo = NULL;
663 uint32_t connectors[MAX_CLONED_CONNECTORS];
664 int n_conn = 0;
665 struct timespec now;
666 int ret = 0;
667
668 wl_list_for_each(head, &output->base.head_list, base.output_link) {
669 assert(n_conn < MAX_CLONED_CONNECTORS);
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300670 connectors[n_conn++] = head->connector.connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100671 }
672
673 /* If disable_planes is set then assign_planes() wasn't
674 * called for this render, so we could still have a stale
675 * cursor plane set up.
676 */
677 if (output->base.disable_planes) {
Alexandros Frantzis10937fe2021-06-14 13:09:44 +0300678 drm_output_set_cursor_view(output, NULL);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100679 if (output->cursor_plane) {
680 output->cursor_plane->base.x = INT32_MIN;
681 output->cursor_plane->base.y = INT32_MIN;
682 }
683 }
684
685 if (state->dpms != WESTON_DPMS_ON) {
686 if (output->cursor_plane) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300687 ret = drmModeSetCursor(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100688 0, 0, 0);
689 if (ret)
690 weston_log("drmModeSetCursor failed disable: %s\n",
691 strerror(errno));
692 }
693
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300694 ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, 0, 0, 0,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100695 NULL, 0, NULL);
696 if (ret)
697 weston_log("drmModeSetCrtc failed disabling: %s\n",
698 strerror(errno));
699
700 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
701 weston_compositor_read_presentation_clock(output->base.compositor, &now);
702 drm_output_update_complete(output,
703 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
704 now.tv_sec, now.tv_nsec / 1000);
705
706 return 0;
707 }
708
709 scanout_state =
710 drm_output_state_get_existing_plane(state, scanout_plane);
711
712 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
713 * legacy PageFlip API doesn't allow us to do clipping either. */
714 assert(scanout_state->src_x == 0);
715 assert(scanout_state->src_y == 0);
716 assert(scanout_state->src_w ==
717 (unsigned) (output->base.current_mode->width << 16));
718 assert(scanout_state->src_h ==
719 (unsigned) (output->base.current_mode->height << 16));
720 assert(scanout_state->dest_x == 0);
721 assert(scanout_state->dest_y == 0);
722 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
723 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
724 /* The legacy SetCrtc API doesn't support fences */
725 assert(scanout_state->in_fence_fd == -1);
726
727 mode = to_drm_mode(output->base.current_mode);
728 if (backend->state_invalid ||
729 !scanout_plane->state_cur->fb ||
730 scanout_plane->state_cur->fb->strides[0] !=
731 scanout_state->fb->strides[0]) {
732
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300733 ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100734 scanout_state->fb->fb_id,
735 0, 0,
736 connectors, n_conn,
737 &mode->mode_info);
738 if (ret) {
739 weston_log("set mode failed: %s\n", strerror(errno));
740 goto err;
741 }
742 }
743
744 pinfo = scanout_state->fb->format;
745 drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300746 crtc->crtc_id, scanout_state->plane->plane_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100747 pinfo ? pinfo->drm_format_name : "UNKNOWN");
748
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300749 if (drmModePageFlip(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100750 scanout_state->fb->fb_id,
751 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
752 weston_log("queueing pageflip failed: %s\n", strerror(errno));
753 goto err;
754 }
755
756 assert(!output->page_flip_pending);
757
758 if (output->pageflip_timer)
759 wl_event_source_timer_update(output->pageflip_timer,
760 backend->pageflip_timeout);
761
762 drm_output_set_cursor(state);
763
764 if (state->dpms != output->state_cur->dpms) {
765 wl_list_for_each(head, &output->base.head_list, base.output_link) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300766 dpms_prop = &head->connector.props[WDRM_CONNECTOR_DPMS];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100767 if (dpms_prop->prop_id == 0)
768 continue;
769
770 ret = drmModeConnectorSetProperty(backend->drm.fd,
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300771 head->connector.connector_id,
772 dpms_prop->prop_id,
773 state->dpms);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100774 if (ret) {
775 weston_log("DRM: DPMS: failed property set for %s\n",
776 head->base.name);
777 }
778 }
779 }
780
781 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
782
783 return 0;
784
785err:
Alexandros Frantzis10937fe2021-06-14 13:09:44 +0300786 drm_output_set_cursor_view(output, NULL);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100787 drm_output_state_free(state);
788 return -1;
789}
790
Daniel Stone4c2fc702019-06-18 11:12:07 +0100791static int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300792crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100793 enum wdrm_crtc_property prop, uint64_t val)
794{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300795 struct drm_property_info *info = &crtc->props_crtc[prop];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100796 int ret;
797
798 if (info->prop_id == 0)
799 return -1;
800
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300801 ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100802 val);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300803 drm_debug(crtc->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
804 (unsigned long) crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100805 (unsigned long) info->prop_id, info->name,
806 (unsigned long long) val, (unsigned long long) val);
807 return (ret <= 0) ? -1 : 0;
808}
809
810static int
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300811connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100812 enum wdrm_connector_property prop, uint64_t val)
813{
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300814 struct drm_property_info *info = &connector->props[prop];
815 uint32_t connector_id = connector->connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100816 int ret;
817
818 if (info->prop_id == 0)
819 return -1;
820
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300821 ret = drmModeAtomicAddProperty(req, connector_id, info->prop_id, val);
822 drm_debug(connector->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
823 (unsigned long) connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100824 (unsigned long) info->prop_id, info->name,
825 (unsigned long long) val, (unsigned long long) val);
826 return (ret <= 0) ? -1 : 0;
827}
828
829static int
830plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
831 enum wdrm_plane_property prop, uint64_t val)
832{
833 struct drm_property_info *info = &plane->props[prop];
834 int ret;
835
836 if (info->prop_id == 0)
837 return -1;
838
839 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
840 val);
841 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
842 (unsigned long) plane->plane_id,
843 (unsigned long) info->prop_id, info->name,
844 (unsigned long long) val, (unsigned long long) val);
845 return (ret <= 0) ? -1 : 0;
846}
847
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530848static bool
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300849drm_connector_has_prop(struct drm_connector *connector,
850 enum wdrm_connector_property prop)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530851{
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300852 if (connector->props[prop].prop_id != 0)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530853 return true;
854
855 return false;
856}
857
858/*
859 * This function converts the protection requests from weston_hdcp_protection
860 * corresponding drm values. These values can be set in "Content Protection"
861 * & "HDCP Content Type" connector properties.
862 */
863static void
864get_drm_protection_from_weston(enum weston_hdcp_protection weston_protection,
865 enum wdrm_content_protection_state *drm_protection,
866 enum wdrm_hdcp_content_type *drm_cp_type)
867{
868
869 switch (weston_protection) {
870 case WESTON_HDCP_DISABLE:
871 *drm_protection = WDRM_CONTENT_PROTECTION_UNDESIRED;
872 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
873 break;
874 case WESTON_HDCP_ENABLE_TYPE_0:
875 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
876 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
877 break;
878 case WESTON_HDCP_ENABLE_TYPE_1:
879 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
880 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE1;
881 break;
882 default:
883 assert(0 && "bad weston_hdcp_protection");
884 }
885}
886
887static void
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300888drm_connector_set_hdcp_property(struct drm_connector *connector,
889 enum weston_hdcp_protection protection,
890 drmModeAtomicReq *req)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530891{
892 int ret;
893 enum wdrm_content_protection_state drm_protection;
894 enum wdrm_hdcp_content_type drm_cp_type;
895 struct drm_property_enum_info *enum_info;
896 uint64_t prop_val;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300897 struct drm_property_info *props = connector->props;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530898
899 get_drm_protection_from_weston(protection, &drm_protection,
900 &drm_cp_type);
901
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300902 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_CONTENT_PROTECTION))
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530903 return;
904
905 /*
906 * Content-type property is not exposed for platforms not supporting
907 * HDCP2.2, therefore, type-1 cannot be supported. The type-0 content
908 * still can be supported if the content-protection property is exposed.
909 */
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300910 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE) &&
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530911 drm_cp_type != WDRM_HDCP_CONTENT_TYPE0)
912 return;
913
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300914 enum_info = props[WDRM_CONNECTOR_CONTENT_PROTECTION].enum_values;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530915 prop_val = enum_info[drm_protection].value;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300916 ret = connector_add_prop(req, connector,
917 WDRM_CONNECTOR_CONTENT_PROTECTION, prop_val);
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530918 assert(ret == 0);
919
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300920 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE))
Ankit Nautiyalfc2c1802019-08-30 19:40:46 +0530921 return;
922
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300923 enum_info = props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE].enum_values;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530924 prop_val = enum_info[drm_cp_type].value;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300925 ret = connector_add_prop(req, connector,
926 WDRM_CONNECTOR_HDCP_CONTENT_TYPE, prop_val);
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530927 assert(ret == 0);
928}
929
Daniel Stone4c2fc702019-06-18 11:12:07 +0100930static int
931drm_output_apply_state_atomic(struct drm_output_state *state,
932 drmModeAtomicReq *req,
933 uint32_t *flags)
934{
935 struct drm_output *output = state->output;
936 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300937 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100938 struct drm_plane_state *plane_state;
939 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
940 struct drm_head *head;
941 int ret = 0;
942
943 drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
944 (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
945 (unsigned long) output->base.id, output->base.name);
946
947 if (state->dpms != output->state_cur->dpms) {
948 drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
949 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
950 }
951
952 if (state->dpms == WESTON_DPMS_ON) {
953 ret = drm_mode_ensure_blob(b, current_mode);
954 if (ret != 0)
955 return ret;
956
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300957 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100958 current_mode->blob_id);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300959 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 1);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100960
961 /* No need for the DPMS property, since it is implicit in
962 * routing and CRTC activity. */
963 wl_list_for_each(head, &output->base.head_list, base.output_link) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300964 ret |= connector_add_prop(req, &head->connector,
965 WDRM_CONNECTOR_CRTC_ID,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300966 crtc->crtc_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100967 }
968 } else {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300969 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
970 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100971
972 /* No need for the DPMS property, since it is implicit in
973 * routing and CRTC activity. */
974 wl_list_for_each(head, &output->base.head_list, base.output_link)
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300975 ret |= connector_add_prop(req, &head->connector,
976 WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100977 }
978
Daniel Stone4c2fc702019-06-18 11:12:07 +0100979 if (ret != 0) {
980 weston_log("couldn't set atomic CRTC/connector state\n");
981 return ret;
982 }
983
984 wl_list_for_each(plane_state, &state->plane_list, link) {
985 struct drm_plane *plane = plane_state->plane;
986 const struct pixel_format_info *pinfo = NULL;
leng.fang32af9fc2024-06-13 11:22:15 +0800987 if ( !plane_state->fb )
988 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100989
990 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
991 plane_state->fb ? plane_state->fb->fb_id : 0);
leng.fang32af9fc2024-06-13 11:22:15 +0800992
993 drm_update_video_plane_info(plane_state, flags);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100994 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300995 plane_state->fb ? crtc->crtc_id : 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100996 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
997 plane_state->src_x);
998 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
999 plane_state->src_y);
1000 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
1001 plane_state->src_w);
1002 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
1003 plane_state->src_h);
1004 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
1005 plane_state->dest_x);
1006 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
1007 plane_state->dest_y);
1008 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
1009 plane_state->dest_w);
1010 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
1011 plane_state->dest_h);
Scott Anderson15c603c2020-06-02 17:39:43 +12001012 if (plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS].prop_id != 0)
1013 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS,
1014 plane_state->damage_blob_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001015
1016 if (plane_state->fb && plane_state->fb->format)
1017 pinfo = plane_state->fb->format;
1018
1019 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
1020 (unsigned long) plane->plane_id,
1021 pinfo ? pinfo->drm_format_name : "UNKNOWN");
1022
1023 if (plane_state->in_fence_fd >= 0) {
1024 ret |= plane_add_prop(req, plane,
1025 WDRM_PLANE_IN_FENCE_FD,
1026 plane_state->in_fence_fd);
1027 }
leng.fang32af9fc2024-06-13 11:22:15 +08001028#ifdef USE_DEFAULT_Z_ORDER
1029 //use drm default palne z-order
1030#else
Marius Vladcdd6fa22019-08-29 20:42:00 +03001031 /* do note, that 'invented' zpos values are set as immutable */
1032 if (plane_state->zpos != DRM_PLANE_ZPOS_INVALID_PLANE &&
1033 plane_state->plane->zpos_min != plane_state->plane->zpos_max)
1034 ret |= plane_add_prop(req, plane,
1035 WDRM_PLANE_ZPOS,
1036 plane_state->zpos);
leng.fang32af9fc2024-06-13 11:22:15 +08001037#endif
Marius Vladcdd6fa22019-08-29 20:42:00 +03001038
Daniel Stone4c2fc702019-06-18 11:12:07 +01001039 if (ret != 0) {
1040 weston_log("couldn't set plane state\n");
1041 return ret;
1042 }
1043 }
1044
1045 return 0;
1046}
1047
1048/**
1049 * Helper function used only by drm_pending_state_apply, with the same
1050 * guarantees and constraints as that function.
1051 */
1052static int
1053drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
1054 enum drm_state_apply_mode mode)
1055{
1056 struct drm_backend *b = pending_state->backend;
1057 struct drm_output_state *output_state, *tmp;
1058 struct drm_plane *plane;
1059 drmModeAtomicReq *req = drmModeAtomicAlloc();
1060 uint32_t flags;
1061 int ret = 0;
1062
1063 if (!req)
1064 return -1;
1065
1066 switch (mode) {
1067 case DRM_STATE_APPLY_SYNC:
1068 flags = 0;
1069 break;
1070 case DRM_STATE_APPLY_ASYNC:
1071 flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
1072 break;
1073 case DRM_STATE_TEST_ONLY:
1074 flags = DRM_MODE_ATOMIC_TEST_ONLY;
1075 break;
1076 }
1077
1078 if (b->state_invalid) {
1079 struct weston_head *head_base;
1080 struct drm_head *head;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001081 struct drm_crtc *crtc;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001082 uint32_t connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001083 int err;
1084
1085 drm_debug(b, "\t\t[atomic] previous state invalid; "
1086 "starting with fresh state\n");
1087
1088 /* If we need to reset all our state (e.g. because we've
1089 * just started, or just been VT-switched in), explicitly
1090 * disable all the CRTCs and connectors we aren't using. */
leng.fang32af9fc2024-06-13 11:22:15 +08001091#if 0
1092
Daniel Stone4c2fc702019-06-18 11:12:07 +01001093 wl_list_for_each(head_base,
1094 &b->compositor->head_list, compositor_link) {
1095 struct drm_property_info *info;
1096
1097 if (weston_head_is_enabled(head_base))
1098 continue;
1099
1100 head = to_drm_head(head_base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001101 connector_id = head->connector.connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001102
1103 drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
1104 head_base->name);
1105
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001106 info = &head->connector.props[WDRM_CONNECTOR_CRTC_ID];
1107 err = drmModeAtomicAddProperty(req, connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001108 info->prop_id, 0);
1109 drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001110 (unsigned long) connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001111 (unsigned long) info->prop_id,
1112 info->name);
1113 if (err <= 0)
1114 ret = -1;
1115 }
1116
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001117 wl_list_for_each(crtc, &b->crtc_list, link) {
Daniel Stone4c2fc702019-06-18 11:12:07 +01001118 struct drm_property_info *info;
1119 drmModeObjectProperties *props;
1120 uint64_t active;
1121
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001122 /* Ignore CRTCs that are in use */
1123 if (crtc->output)
1124 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001125
1126 /* We can't emit a disable on a CRTC that's already
1127 * off, as the kernel will refuse to generate an event
1128 * for an off->off state and fail the commit.
1129 */
1130 props = drmModeObjectGetProperties(b->drm.fd,
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001131 crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001132 DRM_MODE_OBJECT_CRTC);
1133 if (!props) {
1134 ret = -1;
1135 continue;
1136 }
1137
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001138 info = &crtc->props_crtc[WDRM_CRTC_ACTIVE];
Daniel Stone4c2fc702019-06-18 11:12:07 +01001139 active = drm_property_get_value(info, props, 0);
1140 drmModeFreeObjectProperties(props);
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001141 if (active == 0)
Daniel Stone4c2fc702019-06-18 11:12:07 +01001142 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001143
1144 drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001145 (unsigned long) crtc->crtc_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001146
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001147 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
1148 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001149 }
leng.fang32af9fc2024-06-13 11:22:15 +08001150#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001151
1152 /* Disable all the planes; planes which are being used will
1153 * override this state in the output-state application. */
1154 wl_list_for_each(plane, &b->plane_list, link) {
1155 drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
1156 (unsigned long) plane->plane_id);
1157 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
1158 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
1159 }
1160
leng.fang32af9fc2024-06-13 11:22:15 +08001161 if (b->allow_modeset)
1162 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001163 }
1164
1165 wl_list_for_each(output_state, &pending_state->output_list, link) {
1166 if (output_state->output->virtual)
1167 continue;
1168 if (mode == DRM_STATE_APPLY_SYNC)
1169 assert(output_state->dpms == WESTON_DPMS_OFF);
1170 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
1171 }
1172
1173 if (ret != 0) {
1174 weston_log("atomic: couldn't compile atomic state\n");
1175 goto out;
1176 }
leng.fang32af9fc2024-06-13 11:22:15 +08001177#ifdef ENABLE_DRM_HELP
1178 ret |= help_atomic_req_add_prop(req);
1179#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001180
leng.fang91856072024-06-07 14:12:54 +08001181#ifdef ENABLE_MODE_POLICY
leng.fangb1081a32024-06-25 14:41:37 +08001182 if (mode != DRM_STATE_TEST_ONLY &&
1183 mode_policy_add_prop(req) > 0) {
1184 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
1185 }
leng.fang91856072024-06-07 14:12:54 +08001186#endif
1187
Daniel Stone4c2fc702019-06-18 11:12:07 +01001188 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
1189 drm_debug(b, "[atomic] drmModeAtomicCommit\n");
1190
leng.fang32af9fc2024-06-13 11:22:15 +08001191 drm_update_buffer_commit_result(ret, pending_state);
1192
Daniel Stone4c2fc702019-06-18 11:12:07 +01001193 /* Test commits do not take ownership of the state; return
1194 * without freeing here. */
1195 if (mode == DRM_STATE_TEST_ONLY) {
1196 drmModeAtomicFree(req);
1197 return ret;
1198 }
1199
1200 if (ret != 0) {
1201 weston_log("atomic: couldn't commit new state: %s\n",
1202 strerror(errno));
1203 goto out;
1204 }
1205
1206 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1207 link)
1208 drm_output_assign_state(output_state, mode);
1209
1210 b->state_invalid = false;
1211
leng.fang32af9fc2024-06-13 11:22:15 +08001212 if (b->allow_modeset)
1213 b->allow_modeset = false;
1214
Daniel Stone4c2fc702019-06-18 11:12:07 +01001215 assert(wl_list_empty(&pending_state->output_list));
1216
1217out:
1218 drmModeAtomicFree(req);
1219 drm_pending_state_free(pending_state);
1220 return ret;
1221}
Daniel Stone4c2fc702019-06-18 11:12:07 +01001222
1223/**
1224 * Tests a pending state, to see if the kernel will accept the update as
1225 * constructed.
1226 *
1227 * Using atomic modesetting, the kernel performs the same checks as it would
1228 * on a real commit, returning success or failure without actually modifying
1229 * the running state. It does not return -EBUSY if there are pending updates
1230 * in flight, so states may be tested at any point, however this means a
1231 * state which passed testing may fail on a real commit if the timing is not
1232 * respected (e.g. committing before the previous commit has completed).
1233 *
1234 * Without atomic modesetting, we have no way to check, so we optimistically
1235 * claim it will work.
1236 *
1237 * Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
1238 * function does _not_ take ownership of pending_state, nor does it clear
1239 * state_invalid.
1240 */
1241int
1242drm_pending_state_test(struct drm_pending_state *pending_state)
1243{
Daniel Stone4c2fc702019-06-18 11:12:07 +01001244 struct drm_backend *b = pending_state->backend;
1245
1246 if (b->atomic_modeset)
1247 return drm_pending_state_apply_atomic(pending_state,
1248 DRM_STATE_TEST_ONLY);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001249
1250 /* We have no way to test state before application on the legacy
1251 * modesetting API, so just claim it succeeded. */
1252 return 0;
1253}
1254
1255/**
1256 * Applies all of a pending_state asynchronously: the primary entry point for
1257 * applying KMS state to a device. Updates the state for all outputs in the
1258 * pending_state, as well as disabling any unclaimed outputs.
1259 *
1260 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1261 */
1262int
1263drm_pending_state_apply(struct drm_pending_state *pending_state)
1264{
1265 struct drm_backend *b = pending_state->backend;
1266 struct drm_output_state *output_state, *tmp;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001267 struct drm_crtc *crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001268
Daniel Stone4c2fc702019-06-18 11:12:07 +01001269 if (b->atomic_modeset)
1270 return drm_pending_state_apply_atomic(pending_state,
1271 DRM_STATE_APPLY_ASYNC);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001272
1273 if (b->state_invalid) {
1274 /* If we need to reset all our state (e.g. because we've
1275 * just started, or just been VT-switched in), explicitly
1276 * disable all the CRTCs we aren't using. This also disables
1277 * all connectors on these CRTCs, so we don't need to do that
1278 * separately with the pre-atomic API. */
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001279 wl_list_for_each(crtc, &b->crtc_list, link) {
1280 if (crtc->output)
1281 continue;
1282 drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
1283 NULL, 0, NULL);
1284 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001285 }
1286
1287 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1288 link) {
1289 struct drm_output *output = output_state->output;
1290 int ret;
1291
1292 if (output->virtual) {
1293 drm_output_assign_state(output_state,
1294 DRM_STATE_APPLY_ASYNC);
1295 continue;
1296 }
1297
1298 ret = drm_output_apply_state_legacy(output_state);
1299 if (ret != 0) {
1300 weston_log("Couldn't apply state for output %s\n",
1301 output->base.name);
nerdopolisd2a320d2021-08-23 21:29:42 -04001302 weston_output_repaint_failed(&output->base);
1303 drm_output_state_free(output->state_cur);
1304 output->state_cur = drm_output_state_alloc(output, NULL);
1305 b->state_invalid = true;
1306 if (!b->use_pixman) {
1307 drm_output_fini_egl(output);
1308 drm_output_init_egl(output, b);
1309 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001310 }
1311 }
1312
1313 b->state_invalid = false;
1314
1315 assert(wl_list_empty(&pending_state->output_list));
1316
1317 drm_pending_state_free(pending_state);
1318
1319 return 0;
1320}
1321
1322/**
1323 * The synchronous version of drm_pending_state_apply. May only be used to
1324 * disable outputs. Does so synchronously: the request is guaranteed to have
1325 * completed on return, and the output will not be touched afterwards.
1326 *
1327 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1328 */
1329int
1330drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
1331{
1332 struct drm_backend *b = pending_state->backend;
1333 struct drm_output_state *output_state, *tmp;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001334 struct drm_crtc *crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001335
Daniel Stone4c2fc702019-06-18 11:12:07 +01001336 if (b->atomic_modeset)
1337 return drm_pending_state_apply_atomic(pending_state,
1338 DRM_STATE_APPLY_SYNC);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001339
1340 if (b->state_invalid) {
1341 /* If we need to reset all our state (e.g. because we've
1342 * just started, or just been VT-switched in), explicitly
1343 * disable all the CRTCs we aren't using. This also disables
1344 * all connectors on these CRTCs, so we don't need to do that
1345 * separately with the pre-atomic API. */
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001346 wl_list_for_each(crtc, &b->crtc_list, link) {
1347 if (crtc->output)
1348 continue;
1349 drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
1350 NULL, 0, NULL);
1351 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001352 }
1353
1354 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1355 link) {
1356 int ret;
1357
1358 assert(output_state->dpms == WESTON_DPMS_OFF);
1359 ret = drm_output_apply_state_legacy(output_state);
1360 if (ret != 0) {
1361 weston_log("Couldn't apply state for output %s\n",
1362 output_state->output->base.name);
1363 }
1364 }
1365
1366 b->state_invalid = false;
1367
1368 assert(wl_list_empty(&pending_state->output_list));
1369
1370 drm_pending_state_free(pending_state);
1371
1372 return 0;
1373}
1374
1375void
1376drm_output_update_msc(struct drm_output *output, unsigned int seq)
1377{
1378 uint64_t msc_hi = output->base.msc >> 32;
1379
1380 if (seq < (output->base.msc & 0xffffffff))
1381 msc_hi++;
1382
1383 output->base.msc = (msc_hi << 32) + seq;
1384}
1385
1386static void
1387page_flip_handler(int fd, unsigned int frame,
1388 unsigned int sec, unsigned int usec, void *data)
1389{
1390 struct drm_output *output = data;
1391 struct drm_backend *b = to_drm_backend(output->base.compositor);
1392 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1393 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1394 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1395
1396 drm_output_update_msc(output, frame);
1397
1398 assert(!b->atomic_modeset);
1399 assert(output->page_flip_pending);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001400 output->page_flip_pending = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001401
1402 drm_output_update_complete(output, flags, sec, usec);
1403}
1404
Daniel Stone4c2fc702019-06-18 11:12:07 +01001405static void
1406atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
1407 unsigned int usec, unsigned int crtc_id, void *data)
1408{
1409 struct drm_backend *b = data;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001410 struct drm_crtc *crtc;
1411 struct drm_output *output;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001412 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1413 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1414 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1415
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001416 crtc = drm_crtc_find(b, crtc_id);
1417 assert(crtc);
1418
1419 output = crtc->output;
1420
leng.fang32af9fc2024-06-13 11:22:15 +08001421 if (crtc->output_change) {
1422 output = crtc->disable_output;
1423 }
1424
Daniel Stone4c2fc702019-06-18 11:12:07 +01001425 /* During the initial modeset, we can disable CRTCs which we don't
1426 * actually handle during normal operation; this will give us events
1427 * for unknown outputs. Ignore them. */
leng.fang32af9fc2024-06-13 11:22:15 +08001428 if ( (!output || !output->base.enabled) && !crtc->output_change)
Daniel Stone4c2fc702019-06-18 11:12:07 +01001429 return;
1430
1431 drm_output_update_msc(output, frame);
1432
leng.fang32af9fc2024-06-13 11:22:15 +08001433 drm_debug(b, "[atomic][CRTC:%u] flip processing started output_change:%d\n",
1434 crtc_id,crtc->output_change );
1435 if ( b->atomic_modeset && output->atomic_complete_pending) {
1436 //assert(b->atomic_modeset);
1437 //assert(output->atomic_complete_pending);
1438 output->atomic_complete_pending = false;
1439 drm_output_update_complete(output, flags, sec, usec);
1440 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001441
leng.fang32af9fc2024-06-13 11:22:15 +08001442 crtc->output_change = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001443 drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
leng.fang32af9fc2024-06-13 11:22:15 +08001444 atomic_flip_handler_time(b);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001445}
Daniel Stone4c2fc702019-06-18 11:12:07 +01001446
1447int
1448on_drm_input(int fd, uint32_t mask, void *data)
1449{
Daniel Stone4c2fc702019-06-18 11:12:07 +01001450 struct drm_backend *b = data;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001451 drmEventContext evctx;
1452
1453 memset(&evctx, 0, sizeof evctx);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001454 evctx.version = 3;
1455 if (b->atomic_modeset)
1456 evctx.page_flip_handler2 = atomic_flip_handler;
1457 else
Daniel Stone4c2fc702019-06-18 11:12:07 +01001458 evctx.page_flip_handler = page_flip_handler;
1459 drmHandleEvent(fd, &evctx);
1460
1461 return 1;
1462}
1463
1464int
1465init_kms_caps(struct drm_backend *b)
1466{
1467 uint64_t cap;
1468 int ret;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001469
1470 weston_log("using %s\n", b->drm.filename);
1471
1472 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Pekka Paalanenf48277b2021-05-10 11:44:57 +03001473 if (ret != 0 || cap != 1) {
1474 weston_log("Error: kernel DRM KMS does not support DRM_CAP_TIMESTAMP_MONOTONIC.\n");
1475 return -1;
1476 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001477
Pekka Paalanenf48277b2021-05-10 11:44:57 +03001478 if (weston_compositor_set_presentation_clock(b->compositor, CLOCK_MONOTONIC) < 0) {
1479 weston_log("Error: failed to set presentation clock to CLOCK_MONOTONIC.\n");
Daniel Stone4c2fc702019-06-18 11:12:07 +01001480 return -1;
1481 }
1482
1483 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
1484 if (ret == 0)
1485 b->cursor_width = cap;
1486 else
1487 b->cursor_width = 64;
1488
1489 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1490 if (ret == 0)
1491 b->cursor_height = cap;
1492 else
1493 b->cursor_height = 64;
1494
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001495 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1496 if (ret) {
1497 weston_log("Error: drm card doesn't support universal planes!\n");
1498 return -1;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001499 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001500
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001501 if (!getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone4c2fc702019-06-18 11:12:07 +01001502 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
1503 if (ret != 0)
1504 cap = 0;
1505 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
1506 b->atomic_modeset = ((ret == 0) && (cap == 1));
1507 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001508 weston_log("DRM: %s atomic modesetting\n",
1509 b->atomic_modeset ? "supports" : "does not support");
1510
Stefan Agner465ab2c2020-06-17 23:36:44 +02001511 if (!getenv("WESTON_DISABLE_GBM_MODIFIERS")) {
1512 ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
1513 if (ret == 0)
1514 b->fb_modifiers = cap;
1515 }
1516 weston_log("DRM: %s GBM modifiers\n",
1517 b->fb_modifiers ? "supports" : "does not support");
Daniel Stone4c2fc702019-06-18 11:12:07 +01001518
Leandro Ribeiro96bef052020-09-09 15:23:49 -03001519 drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
1520
Daniel Stone4c2fc702019-06-18 11:12:07 +01001521 /*
1522 * KMS support for hardware planes cannot properly synchronize
1523 * without nuclear page flip. Without nuclear/atomic, hw plane
1524 * and cursor plane updates would either tear or cause extra
1525 * waits for vblanks which means dropping the compositor framerate
1526 * to a fraction. For cursors, it's not so bad, so they are
1527 * enabled.
1528 */
1529 if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001530 b->sprites_are_broken = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001531
1532 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
1533 b->aspect_ratio_supported = (ret == 0);
1534 weston_log("DRM: %s picture aspect ratio\n",
1535 b->aspect_ratio_supported ? "supports" : "does not support");
1536
1537 return 0;
1538}