blob: 54c28329f212336d014fa2a3fe6292eb0785076e [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"
limin.tianc616dad2024-07-15 11:35:38 +000046#include "shared/timespec-util.h"
leng.fang32af9fc2024-06-13 11:22:15 +080047
Daniel Stone4c2fc702019-06-18 11:12:07 +010048struct drm_property_enum_info plane_type_enums[] = {
49 [WDRM_PLANE_TYPE_PRIMARY] = {
50 .name = "Primary",
51 },
52 [WDRM_PLANE_TYPE_OVERLAY] = {
53 .name = "Overlay",
54 },
55 [WDRM_PLANE_TYPE_CURSOR] = {
56 .name = "Cursor",
57 },
58};
59
60const struct drm_property_info plane_props[] = {
61 [WDRM_PLANE_TYPE] = {
62 .name = "type",
63 .enum_values = plane_type_enums,
64 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
65 },
66 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
67 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
68 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
69 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
70 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
71 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
72 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
73 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
74 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
75 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
76 [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" },
77 [WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
78 [WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
Marius Vladcdd6fa22019-08-29 20:42:00 +030079 [WDRM_PLANE_ZPOS] = { .name = "zpos" },
Daniel Stone4c2fc702019-06-18 11:12:07 +010080};
81
82struct drm_property_enum_info dpms_state_enums[] = {
83 [WDRM_DPMS_STATE_OFF] = {
84 .name = "Off",
85 },
86 [WDRM_DPMS_STATE_ON] = {
87 .name = "On",
88 },
89 [WDRM_DPMS_STATE_STANDBY] = {
90 .name = "Standby",
91 },
92 [WDRM_DPMS_STATE_SUSPEND] = {
93 .name = "Suspend",
94 },
95};
96
Ankit Nautiyala344fe32019-05-14 18:36:08 +053097struct drm_property_enum_info content_protection_enums[] = {
98 [WDRM_CONTENT_PROTECTION_UNDESIRED] = {
99 .name = "Undesired",
100 },
101 [WDRM_CONTENT_PROTECTION_DESIRED] = {
102 .name = "Desired",
103 },
104 [WDRM_CONTENT_PROTECTION_ENABLED] = {
105 .name = "Enabled",
106 },
107};
108
109struct drm_property_enum_info hdcp_content_type_enums[] = {
110 [WDRM_HDCP_CONTENT_TYPE0] = {
111 .name = "HDCP Type0",
112 },
113 [WDRM_HDCP_CONTENT_TYPE1] = {
114 .name = "HDCP Type1",
115 },
116};
117
Lucas Stach72e7a1e2019-11-25 23:31:57 +0000118struct drm_property_enum_info panel_orientation_enums[] = {
119 [WDRM_PANEL_ORIENTATION_NORMAL] = { .name = "Normal", },
120 [WDRM_PANEL_ORIENTATION_UPSIDE_DOWN] = { .name = "Upside Down", },
121 [WDRM_PANEL_ORIENTATION_LEFT_SIDE_UP] = { .name = "Left Side Up", },
122 [WDRM_PANEL_ORIENTATION_RIGHT_SIDE_UP] = { .name = "Right Side Up", },
123};
124
Daniel Stone4c2fc702019-06-18 11:12:07 +0100125const struct drm_property_info connector_props[] = {
126 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
127 [WDRM_CONNECTOR_DPMS] = {
128 .name = "DPMS",
129 .enum_values = dpms_state_enums,
130 .num_enum_values = WDRM_DPMS_STATE__COUNT,
131 },
132 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
133 [WDRM_CONNECTOR_NON_DESKTOP] = { .name = "non-desktop", },
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530134 [WDRM_CONNECTOR_CONTENT_PROTECTION] = {
leng.fangdbaf6fa2024-06-20 19:31:04 +0800135 .name = "ContentProtection",
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530136 .enum_values = content_protection_enums,
137 .num_enum_values = WDRM_CONTENT_PROTECTION__COUNT,
138 },
139 [WDRM_CONNECTOR_HDCP_CONTENT_TYPE] = {
140 .name = "HDCP Content Type",
141 .enum_values = hdcp_content_type_enums,
142 .num_enum_values = WDRM_HDCP_CONTENT_TYPE__COUNT,
143 },
Lucas Stach72e7a1e2019-11-25 23:31:57 +0000144 [WDRM_CONNECTOR_PANEL_ORIENTATION] = {
145 .name = "panel orientation",
146 .enum_values = panel_orientation_enums,
147 .num_enum_values = WDRM_PANEL_ORIENTATION__COUNT,
148 },
Daniel Stone4c2fc702019-06-18 11:12:07 +0100149};
150
151const struct drm_property_info crtc_props[] = {
152 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
153 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
154};
155
156
157/**
158 * Mode for drm_pending_state_apply and co.
159 */
160enum drm_state_apply_mode {
161 DRM_STATE_APPLY_SYNC, /**< state fully processed */
162 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
163 DRM_STATE_TEST_ONLY, /**< test if the state can be applied */
164};
165
166/**
167 * Get the current value of a KMS property
168 *
169 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
170 * for the target property, return the current value of that property,
171 * with an optional default. If the property is a KMS enum type, the return
172 * value will be translated into the appropriate internal enum.
173 *
174 * If the property is not present, the default value will be returned.
175 *
176 * @param info Internal structure for property to look up
177 * @param props Raw KMS properties for the target object
178 * @param def Value to return if property is not found
179 */
180uint64_t
181drm_property_get_value(struct drm_property_info *info,
182 const drmModeObjectProperties *props,
183 uint64_t def)
184{
185 unsigned int i;
186
187 if (info->prop_id == 0)
188 return def;
189
190 for (i = 0; i < props->count_props; i++) {
191 unsigned int j;
192
193 if (props->props[i] != info->prop_id)
194 continue;
195
196 /* Simple (non-enum) types can return the value directly */
197 if (info->num_enum_values == 0)
198 return props->prop_values[i];
199
200 /* Map from raw value to enum value */
201 for (j = 0; j < info->num_enum_values; j++) {
202 if (!info->enum_values[j].valid)
203 continue;
204 if (info->enum_values[j].value != props->prop_values[i])
205 continue;
206
207 return j;
208 }
209
210 /* We don't have a mapping for this enum; return default. */
211 break;
212 }
213
214 return def;
215}
216
217/**
Marius Vlad1accffe2019-11-01 12:00:09 +0200218 * Get the current range values of a KMS property
219 *
220 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
221 * for the target property, return the current range values of that property,
222 *
223 * If the property is not present, or there's no it is not a prop range then
224 * NULL will be returned.
225 *
226 * @param info Internal structure for property to look up
227 * @param props Raw KMS properties for the target object
228 */
229uint64_t *
230drm_property_get_range_values(struct drm_property_info *info,
231 const drmModeObjectProperties *props)
232{
233 unsigned int i;
234
235 if (info->prop_id == 0)
236 return NULL;
237
238 for (i = 0; i < props->count_props; i++) {
239
240 if (props->props[i] != info->prop_id)
241 continue;
242
243 if (!(info->flags & DRM_MODE_PROP_RANGE) &&
244 !(info->flags & DRM_MODE_PROP_SIGNED_RANGE))
245 continue;
246
247 return info->range_values;
248 }
249
250 return NULL;
251}
252
253/**
Daniel Stone4c2fc702019-06-18 11:12:07 +0100254 * Cache DRM property values
255 *
256 * Update a per-object array of drm_property_info structures, given the
257 * DRM properties of the object.
258 *
259 * Call this every time an object newly appears (note that only connectors
260 * can be hotplugged), the first time it is seen, or when its status changes
261 * in a way which invalidates the potential property values (currently, the
262 * only case for this is connector hotplug).
263 *
264 * This updates the property IDs and enum values within the drm_property_info
265 * array.
266 *
267 * DRM property enum values are dynamic at runtime; the user must query the
268 * property to find out the desired runtime value for a requested string
269 * name. Using the 'type' field on planes as an example, there is no single
270 * hardcoded constant for primary plane types; instead, the property must be
271 * queried at runtime to find the value associated with the string "Primary".
272 *
273 * This helper queries and caches the enum values, to allow us to use a set
274 * of compile-time-constant enums portably across various implementations.
275 * The values given in enum_names are searched for, and stored in the
276 * same-indexed field of the map array.
277 *
278 * @param b DRM backend object
279 * @param src DRM property info array to source from
280 * @param info DRM property info array to copy into
281 * @param num_infos Number of entries in the source array
282 * @param props DRM object properties for the object
283 */
284void
285drm_property_info_populate(struct drm_backend *b,
286 const struct drm_property_info *src,
287 struct drm_property_info *info,
288 unsigned int num_infos,
289 drmModeObjectProperties *props)
290{
291 drmModePropertyRes *prop;
292 unsigned i, j;
293
294 for (i = 0; i < num_infos; i++) {
295 unsigned int j;
296
297 info[i].name = src[i].name;
298 info[i].prop_id = 0;
299 info[i].num_enum_values = src[i].num_enum_values;
300
301 if (src[i].num_enum_values == 0)
302 continue;
303
304 info[i].enum_values =
305 malloc(src[i].num_enum_values *
306 sizeof(*info[i].enum_values));
307 assert(info[i].enum_values);
308 for (j = 0; j < info[i].num_enum_values; j++) {
309 info[i].enum_values[j].name = src[i].enum_values[j].name;
310 info[i].enum_values[j].valid = false;
311 }
312 }
313
314 for (i = 0; i < props->count_props; i++) {
315 unsigned int k;
316
317 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
318 if (!prop)
319 continue;
320
321 for (j = 0; j < num_infos; j++) {
322 if (!strcmp(prop->name, info[j].name))
323 break;
324 }
325
326 /* We don't know/care about this property. */
327 if (j == num_infos) {
328#ifdef DEBUG
329 weston_log("DRM debug: unrecognized property %u '%s'\n",
330 prop->prop_id, prop->name);
331#endif
332 drmModeFreeProperty(prop);
333 continue;
334 }
335
336 if (info[j].num_enum_values == 0 &&
337 (prop->flags & DRM_MODE_PROP_ENUM)) {
338 weston_log("DRM: expected property %s to not be an"
339 " enum, but it is; ignoring\n", prop->name);
340 drmModeFreeProperty(prop);
341 continue;
342 }
343
344 info[j].prop_id = props->props[i];
Marius Vlad1accffe2019-11-01 12:00:09 +0200345 info[j].flags = prop->flags;
346
347 if (prop->flags & DRM_MODE_PROP_RANGE ||
348 prop->flags & DRM_MODE_PROP_SIGNED_RANGE) {
349 info[j].num_range_values = prop->count_values;
350 for (int i = 0; i < prop->count_values; i++)
351 info[j].range_values[i] = prop->values[i];
352 }
353
Daniel Stone4c2fc702019-06-18 11:12:07 +0100354
355 if (info[j].num_enum_values == 0) {
356 drmModeFreeProperty(prop);
357 continue;
358 }
359
360 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
361 weston_log("DRM: expected property %s to be an enum,"
362 " but it is not; ignoring\n", prop->name);
363 drmModeFreeProperty(prop);
364 info[j].prop_id = 0;
365 continue;
366 }
367
368 for (k = 0; k < info[j].num_enum_values; k++) {
369 int l;
370
371 for (l = 0; l < prop->count_enums; l++) {
372 if (!strcmp(prop->enums[l].name,
373 info[j].enum_values[k].name))
374 break;
375 }
376
377 if (l == prop->count_enums)
378 continue;
379
380 info[j].enum_values[k].valid = true;
381 info[j].enum_values[k].value = prop->enums[l].value;
382 }
383
384 drmModeFreeProperty(prop);
385 }
386
387#ifdef DEBUG
388 for (i = 0; i < num_infos; i++) {
389 if (info[i].prop_id == 0)
390 weston_log("DRM warning: property '%s' missing\n",
391 info[i].name);
392 }
393#endif
394}
395
396/**
397 * Free DRM property information
398 *
399 * Frees all memory associated with a DRM property info array and zeroes
400 * it out, leaving it usable for a further drm_property_info_update() or
401 * drm_property_info_free().
402 *
403 * @param info DRM property info array
404 * @param num_props Number of entries in array to free
405 */
406void
407drm_property_info_free(struct drm_property_info *info, int num_props)
408{
409 int i;
410
411 for (i = 0; i < num_props; i++)
412 free(info[i].enum_values);
413
414 memset(info, 0, sizeof(*info) * num_props);
415}
416
Daniel Stone4c2fc702019-06-18 11:12:07 +0100417static inline uint32_t *
418formats_ptr(struct drm_format_modifier_blob *blob)
419{
420 return (uint32_t *)(((char *)blob) + blob->formats_offset);
421}
422
423static inline struct drm_format_modifier *
424modifiers_ptr(struct drm_format_modifier_blob *blob)
425{
426 return (struct drm_format_modifier *)
427 (((char *)blob) + blob->modifiers_offset);
428}
Daniel Stone4c2fc702019-06-18 11:12:07 +0100429
430/**
431 * Populates the plane's formats array, using either the IN_FORMATS blob
432 * property (if available), or the plane's format list if not.
433 */
434int
435drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
Stefan Agner465ab2c2020-06-17 23:36:44 +0200436 const drmModeObjectProperties *props,
437 const bool use_modifiers)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100438{
Scott Anderson74663092021-02-01 15:46:33 -0300439 unsigned i, j;
440 drmModePropertyBlobRes *blob = NULL;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100441 struct drm_format_modifier_blob *fmt_mod_blob;
442 struct drm_format_modifier *blob_modifiers;
443 uint32_t *blob_formats;
444 uint32_t blob_id;
Scott Anderson74663092021-02-01 15:46:33 -0300445 struct weston_drm_format *fmt;
446 int ret = 0;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100447
Stefan Agner465ab2c2020-06-17 23:36:44 +0200448 if (!use_modifiers)
449 goto fallback;
450
Daniel Stone4c2fc702019-06-18 11:12:07 +0100451 blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
452 props,
453 0);
454 if (blob_id == 0)
455 goto fallback;
456
457 blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
458 if (!blob)
459 goto fallback;
460
461 fmt_mod_blob = blob->data;
462 blob_formats = formats_ptr(fmt_mod_blob);
463 blob_modifiers = modifiers_ptr(fmt_mod_blob);
464
Scott Anderson74663092021-02-01 15:46:33 -0300465 assert(kplane->count_formats == fmt_mod_blob->count_formats);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100466
467 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
Scott Anderson74663092021-02-01 15:46:33 -0300468 fmt = weston_drm_format_array_add_format(&plane->formats,
469 blob_formats[i]);
470 if (!fmt) {
471 ret = -1;
472 goto out;
473 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100474
475 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
476 struct drm_format_modifier *mod = &blob_modifiers[j];
477
478 if ((i < mod->offset) || (i > mod->offset + 63))
479 continue;
480 if (!(mod->formats & (1 << (i - mod->offset))))
481 continue;
482
Scott Anderson74663092021-02-01 15:46:33 -0300483 ret = weston_drm_format_add_modifier(fmt, mod->modifier);
484 if (ret < 0)
485 goto out;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100486 }
487
Leandro Ribeiro98101e82021-04-21 11:46:35 -0300488 if (fmt->modifiers.size == 0)
489 weston_drm_format_array_remove_latest_format(&plane->formats);
leng.fang32af9fc2024-06-13 11:22:15 +0800490
491 if (fmt->format == DRM_FORMAT_NV12 ||
492 fmt->format == DRM_FORMAT_NV21)
493 plane->is_video_plane = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100494 }
495
Scott Anderson74663092021-02-01 15:46:33 -0300496out:
Daniel Stone4c2fc702019-06-18 11:12:07 +0100497 drmModeFreePropertyBlob(blob);
Scott Anderson74663092021-02-01 15:46:33 -0300498 return ret;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100499
500fallback:
Daniel Stone4c2fc702019-06-18 11:12:07 +0100501 /* No IN_FORMATS blob available, so just use the old. */
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900502 for (i = 0; i < kplane->count_formats; i++) {
Scott Anderson74663092021-02-01 15:46:33 -0300503 fmt = weston_drm_format_array_add_format(&plane->formats,
504 kplane->formats[i]);
505 if (!fmt)
506 return -1;
Leandro Ribeiro567cc922021-04-21 11:44:53 -0300507 ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_INVALID);
Scott Anderson74663092021-02-01 15:46:33 -0300508 if (ret < 0)
509 return -1;
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900510 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100511 return 0;
512}
513
514void
515drm_output_set_gamma(struct weston_output *output_base,
516 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
517{
518 int rc;
519 struct drm_output *output = to_drm_output(output_base);
520 struct drm_backend *backend =
521 to_drm_backend(output->base.compositor);
522
523 /* check */
524 if (output_base->gamma_size != size)
525 return;
526
527 rc = drmModeCrtcSetGamma(backend->drm.fd,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300528 output->crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100529 size, r, g, b);
530 if (rc)
531 weston_log("set gamma failed: %s\n", strerror(errno));
532}
533
534/**
535 * Mark an output state as current on the output, i.e. it has been
536 * submitted to the kernel. The mode argument determines whether this
537 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
538 * or asynchronously (in which case we wait for events to complete).
539 */
540static void
541drm_output_assign_state(struct drm_output_state *state,
542 enum drm_state_apply_mode mode)
543{
544 struct drm_output *output = state->output;
545 struct drm_backend *b = to_drm_backend(output->base.compositor);
546 struct drm_plane_state *plane_state;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530547 struct drm_head *head;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100548
549 assert(!output->state_last);
550
551 if (mode == DRM_STATE_APPLY_ASYNC)
552 output->state_last = output->state_cur;
553 else
554 drm_output_state_free(output->state_cur);
555
556 wl_list_remove(&state->link);
557 wl_list_init(&state->link);
558 state->pending_state = NULL;
559
560 output->state_cur = state;
561
562 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300563 drm_debug(b, "\t[CRTC:%u] setting pending flip\n",
564 output->crtc->crtc_id);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100565 output->atomic_complete_pending = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100566 }
567
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530568 if (b->atomic_modeset &&
569 state->protection == WESTON_HDCP_DISABLE)
570 wl_list_for_each(head, &output->base.head_list, base.output_link)
571 weston_head_set_content_protection_status(&head->base,
572 WESTON_HDCP_DISABLE);
573
Daniel Stone4c2fc702019-06-18 11:12:07 +0100574 /* Replace state_cur on each affected plane with the new state, being
575 * careful to dispose of orphaned (but only orphaned) previous state.
576 * If the previous state is not orphaned (still has an output_state
577 * attached), it will be disposed of by freeing the output_state. */
578 wl_list_for_each(plane_state, &state->plane_list, link) {
579 struct drm_plane *plane = plane_state->plane;
580
581 if (plane->state_cur && !plane->state_cur->output_state)
582 drm_plane_state_free(plane->state_cur, true);
583 plane->state_cur = plane_state;
584
585 if (mode != DRM_STATE_APPLY_ASYNC) {
586 plane_state->complete = true;
587 continue;
588 }
589
590 if (b->atomic_modeset)
591 continue;
592
593 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
594 if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100595 output->page_flip_pending = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100596 }
597}
598
599static void
600drm_output_set_cursor(struct drm_output_state *output_state)
601{
602 struct drm_output *output = output_state->output;
603 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300604 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100605 struct drm_plane *plane = output->cursor_plane;
606 struct drm_plane_state *state;
Stefan Agner974390a2019-07-08 00:42:05 +0200607 uint32_t handle;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100608
609 if (!plane)
610 return;
611
612 state = drm_output_state_get_existing_plane(output_state, plane);
613 if (!state)
614 return;
615
616 if (!state->fb) {
617 pixman_region32_fini(&plane->base.damage);
618 pixman_region32_init(&plane->base.damage);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300619 drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100620 return;
621 }
622
623 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
624 assert(!plane->state_cur->output || plane->state_cur->output == output);
625
Stefan Agner974390a2019-07-08 00:42:05 +0200626 handle = output->gbm_cursor_handle[output->current_cursor];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100627 if (plane->state_cur->fb != state->fb) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300628 if (drmModeSetCursor(b->drm.fd, crtc->crtc_id, handle,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100629 b->cursor_width, b->cursor_height)) {
630 weston_log("failed to set cursor: %s\n",
631 strerror(errno));
632 goto err;
633 }
634 }
635
636 pixman_region32_fini(&plane->base.damage);
637 pixman_region32_init(&plane->base.damage);
638
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300639 if (drmModeMoveCursor(b->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100640 state->dest_x, state->dest_y)) {
641 weston_log("failed to move cursor: %s\n", strerror(errno));
642 goto err;
643 }
644
645 return;
646
647err:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100648 b->cursors_are_broken = true;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300649 drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100650}
651
652static int
653drm_output_apply_state_legacy(struct drm_output_state *state)
654{
655 struct drm_output *output = state->output;
656 struct drm_backend *backend = to_drm_backend(output->base.compositor);
657 struct drm_plane *scanout_plane = output->scanout_plane;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300658 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100659 struct drm_property_info *dpms_prop;
660 struct drm_plane_state *scanout_state;
661 struct drm_mode *mode;
662 struct drm_head *head;
663 const struct pixel_format_info *pinfo = NULL;
664 uint32_t connectors[MAX_CLONED_CONNECTORS];
665 int n_conn = 0;
666 struct timespec now;
667 int ret = 0;
668
669 wl_list_for_each(head, &output->base.head_list, base.output_link) {
670 assert(n_conn < MAX_CLONED_CONNECTORS);
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300671 connectors[n_conn++] = head->connector.connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100672 }
673
674 /* If disable_planes is set then assign_planes() wasn't
675 * called for this render, so we could still have a stale
676 * cursor plane set up.
677 */
678 if (output->base.disable_planes) {
Alexandros Frantzis10937fe2021-06-14 13:09:44 +0300679 drm_output_set_cursor_view(output, NULL);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100680 if (output->cursor_plane) {
681 output->cursor_plane->base.x = INT32_MIN;
682 output->cursor_plane->base.y = INT32_MIN;
683 }
684 }
685
686 if (state->dpms != WESTON_DPMS_ON) {
687 if (output->cursor_plane) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300688 ret = drmModeSetCursor(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100689 0, 0, 0);
690 if (ret)
691 weston_log("drmModeSetCursor failed disable: %s\n",
692 strerror(errno));
693 }
694
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300695 ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, 0, 0, 0,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100696 NULL, 0, NULL);
697 if (ret)
698 weston_log("drmModeSetCrtc failed disabling: %s\n",
699 strerror(errno));
700
701 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
702 weston_compositor_read_presentation_clock(output->base.compositor, &now);
703 drm_output_update_complete(output,
704 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
705 now.tv_sec, now.tv_nsec / 1000);
706
707 return 0;
708 }
709
710 scanout_state =
711 drm_output_state_get_existing_plane(state, scanout_plane);
712
713 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
714 * legacy PageFlip API doesn't allow us to do clipping either. */
715 assert(scanout_state->src_x == 0);
716 assert(scanout_state->src_y == 0);
717 assert(scanout_state->src_w ==
718 (unsigned) (output->base.current_mode->width << 16));
719 assert(scanout_state->src_h ==
720 (unsigned) (output->base.current_mode->height << 16));
721 assert(scanout_state->dest_x == 0);
722 assert(scanout_state->dest_y == 0);
723 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
724 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
725 /* The legacy SetCrtc API doesn't support fences */
726 assert(scanout_state->in_fence_fd == -1);
727
728 mode = to_drm_mode(output->base.current_mode);
729 if (backend->state_invalid ||
730 !scanout_plane->state_cur->fb ||
731 scanout_plane->state_cur->fb->strides[0] !=
732 scanout_state->fb->strides[0]) {
733
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300734 ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100735 scanout_state->fb->fb_id,
736 0, 0,
737 connectors, n_conn,
738 &mode->mode_info);
739 if (ret) {
740 weston_log("set mode failed: %s\n", strerror(errno));
741 goto err;
742 }
743 }
744
745 pinfo = scanout_state->fb->format;
746 drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300747 crtc->crtc_id, scanout_state->plane->plane_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100748 pinfo ? pinfo->drm_format_name : "UNKNOWN");
749
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300750 if (drmModePageFlip(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100751 scanout_state->fb->fb_id,
752 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
753 weston_log("queueing pageflip failed: %s\n", strerror(errno));
754 goto err;
755 }
756
757 assert(!output->page_flip_pending);
758
759 if (output->pageflip_timer)
760 wl_event_source_timer_update(output->pageflip_timer,
761 backend->pageflip_timeout);
762
763 drm_output_set_cursor(state);
764
765 if (state->dpms != output->state_cur->dpms) {
766 wl_list_for_each(head, &output->base.head_list, base.output_link) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300767 dpms_prop = &head->connector.props[WDRM_CONNECTOR_DPMS];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100768 if (dpms_prop->prop_id == 0)
769 continue;
770
771 ret = drmModeConnectorSetProperty(backend->drm.fd,
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300772 head->connector.connector_id,
773 dpms_prop->prop_id,
774 state->dpms);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100775 if (ret) {
776 weston_log("DRM: DPMS: failed property set for %s\n",
777 head->base.name);
778 }
779 }
780 }
781
782 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
783
784 return 0;
785
786err:
Alexandros Frantzis10937fe2021-06-14 13:09:44 +0300787 drm_output_set_cursor_view(output, NULL);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100788 drm_output_state_free(state);
789 return -1;
790}
791
Daniel Stone4c2fc702019-06-18 11:12:07 +0100792static int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300793crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100794 enum wdrm_crtc_property prop, uint64_t val)
795{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300796 struct drm_property_info *info = &crtc->props_crtc[prop];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100797 int ret;
798
799 if (info->prop_id == 0)
800 return -1;
801
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300802 ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100803 val);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300804 drm_debug(crtc->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
805 (unsigned long) crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100806 (unsigned long) info->prop_id, info->name,
807 (unsigned long long) val, (unsigned long long) val);
808 return (ret <= 0) ? -1 : 0;
809}
810
811static int
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300812connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100813 enum wdrm_connector_property prop, uint64_t val)
814{
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300815 struct drm_property_info *info = &connector->props[prop];
816 uint32_t connector_id = connector->connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100817 int ret;
818
819 if (info->prop_id == 0)
820 return -1;
821
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300822 ret = drmModeAtomicAddProperty(req, connector_id, info->prop_id, val);
823 drm_debug(connector->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
824 (unsigned long) connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100825 (unsigned long) info->prop_id, info->name,
826 (unsigned long long) val, (unsigned long long) val);
827 return (ret <= 0) ? -1 : 0;
828}
829
830static int
831plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
832 enum wdrm_plane_property prop, uint64_t val)
833{
834 struct drm_property_info *info = &plane->props[prop];
835 int ret;
836
837 if (info->prop_id == 0)
838 return -1;
839
840 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
841 val);
842 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
843 (unsigned long) plane->plane_id,
844 (unsigned long) info->prop_id, info->name,
845 (unsigned long long) val, (unsigned long long) val);
846 return (ret <= 0) ? -1 : 0;
847}
848
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530849static bool
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300850drm_connector_has_prop(struct drm_connector *connector,
851 enum wdrm_connector_property prop)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530852{
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300853 if (connector->props[prop].prop_id != 0)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530854 return true;
855
856 return false;
857}
858
859/*
860 * This function converts the protection requests from weston_hdcp_protection
861 * corresponding drm values. These values can be set in "Content Protection"
862 * & "HDCP Content Type" connector properties.
863 */
864static void
865get_drm_protection_from_weston(enum weston_hdcp_protection weston_protection,
866 enum wdrm_content_protection_state *drm_protection,
867 enum wdrm_hdcp_content_type *drm_cp_type)
868{
869
870 switch (weston_protection) {
871 case WESTON_HDCP_DISABLE:
872 *drm_protection = WDRM_CONTENT_PROTECTION_UNDESIRED;
873 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
874 break;
875 case WESTON_HDCP_ENABLE_TYPE_0:
876 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
877 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
878 break;
879 case WESTON_HDCP_ENABLE_TYPE_1:
880 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
881 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE1;
882 break;
883 default:
884 assert(0 && "bad weston_hdcp_protection");
885 }
886}
887
888static void
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300889drm_connector_set_hdcp_property(struct drm_connector *connector,
890 enum weston_hdcp_protection protection,
891 drmModeAtomicReq *req)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530892{
893 int ret;
894 enum wdrm_content_protection_state drm_protection;
895 enum wdrm_hdcp_content_type drm_cp_type;
896 struct drm_property_enum_info *enum_info;
897 uint64_t prop_val;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300898 struct drm_property_info *props = connector->props;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530899
900 get_drm_protection_from_weston(protection, &drm_protection,
901 &drm_cp_type);
902
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300903 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_CONTENT_PROTECTION))
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530904 return;
905
906 /*
907 * Content-type property is not exposed for platforms not supporting
908 * HDCP2.2, therefore, type-1 cannot be supported. The type-0 content
909 * still can be supported if the content-protection property is exposed.
910 */
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300911 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE) &&
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530912 drm_cp_type != WDRM_HDCP_CONTENT_TYPE0)
913 return;
914
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300915 enum_info = props[WDRM_CONNECTOR_CONTENT_PROTECTION].enum_values;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530916 prop_val = enum_info[drm_protection].value;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300917 ret = connector_add_prop(req, connector,
918 WDRM_CONNECTOR_CONTENT_PROTECTION, prop_val);
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530919 assert(ret == 0);
920
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300921 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE))
Ankit Nautiyalfc2c1802019-08-30 19:40:46 +0530922 return;
923
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300924 enum_info = props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE].enum_values;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530925 prop_val = enum_info[drm_cp_type].value;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300926 ret = connector_add_prop(req, connector,
927 WDRM_CONNECTOR_HDCP_CONTENT_TYPE, prop_val);
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530928 assert(ret == 0);
929}
930
Daniel Stone4c2fc702019-06-18 11:12:07 +0100931static int
932drm_output_apply_state_atomic(struct drm_output_state *state,
933 drmModeAtomicReq *req,
934 uint32_t *flags)
935{
936 struct drm_output *output = state->output;
937 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300938 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100939 struct drm_plane_state *plane_state;
940 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
941 struct drm_head *head;
942 int ret = 0;
943
944 drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
945 (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
946 (unsigned long) output->base.id, output->base.name);
947
948 if (state->dpms != output->state_cur->dpms) {
949 drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
950 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
951 }
952
953 if (state->dpms == WESTON_DPMS_ON) {
954 ret = drm_mode_ensure_blob(b, current_mode);
955 if (ret != 0)
956 return ret;
957
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300958 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100959 current_mode->blob_id);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300960 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 1);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100961
962 /* No need for the DPMS property, since it is implicit in
963 * routing and CRTC activity. */
964 wl_list_for_each(head, &output->base.head_list, base.output_link) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300965 ret |= connector_add_prop(req, &head->connector,
966 WDRM_CONNECTOR_CRTC_ID,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300967 crtc->crtc_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100968 }
969 } else {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300970 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
971 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100972
973 /* No need for the DPMS property, since it is implicit in
974 * routing and CRTC activity. */
975 wl_list_for_each(head, &output->base.head_list, base.output_link)
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300976 ret |= connector_add_prop(req, &head->connector,
977 WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100978 }
979
Daniel Stone4c2fc702019-06-18 11:12:07 +0100980 if (ret != 0) {
981 weston_log("couldn't set atomic CRTC/connector state\n");
982 return ret;
983 }
984
985 wl_list_for_each(plane_state, &state->plane_list, link) {
986 struct drm_plane *plane = plane_state->plane;
987 const struct pixel_format_info *pinfo = NULL;
leng.fang32af9fc2024-06-13 11:22:15 +0800988 if ( !plane_state->fb )
989 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100990
991 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
992 plane_state->fb ? plane_state->fb->fb_id : 0);
leng.fang32af9fc2024-06-13 11:22:15 +0800993
994 drm_update_video_plane_info(plane_state, flags);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100995 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300996 plane_state->fb ? crtc->crtc_id : 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100997 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
998 plane_state->src_x);
999 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
1000 plane_state->src_y);
1001 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
1002 plane_state->src_w);
1003 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
1004 plane_state->src_h);
1005 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
1006 plane_state->dest_x);
1007 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
1008 plane_state->dest_y);
1009 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
1010 plane_state->dest_w);
1011 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
1012 plane_state->dest_h);
Scott Anderson15c603c2020-06-02 17:39:43 +12001013 if (plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS].prop_id != 0)
1014 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS,
1015 plane_state->damage_blob_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001016
1017 if (plane_state->fb && plane_state->fb->format)
1018 pinfo = plane_state->fb->format;
1019
1020 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
1021 (unsigned long) plane->plane_id,
1022 pinfo ? pinfo->drm_format_name : "UNKNOWN");
1023
1024 if (plane_state->in_fence_fd >= 0) {
1025 ret |= plane_add_prop(req, plane,
1026 WDRM_PLANE_IN_FENCE_FD,
1027 plane_state->in_fence_fd);
1028 }
leng.fang32af9fc2024-06-13 11:22:15 +08001029#ifdef USE_DEFAULT_Z_ORDER
1030 //use drm default palne z-order
1031#else
Marius Vladcdd6fa22019-08-29 20:42:00 +03001032 /* do note, that 'invented' zpos values are set as immutable */
1033 if (plane_state->zpos != DRM_PLANE_ZPOS_INVALID_PLANE &&
1034 plane_state->plane->zpos_min != plane_state->plane->zpos_max)
1035 ret |= plane_add_prop(req, plane,
1036 WDRM_PLANE_ZPOS,
1037 plane_state->zpos);
leng.fang32af9fc2024-06-13 11:22:15 +08001038#endif
Marius Vladcdd6fa22019-08-29 20:42:00 +03001039
Daniel Stone4c2fc702019-06-18 11:12:07 +01001040 if (ret != 0) {
1041 weston_log("couldn't set plane state\n");
1042 return ret;
1043 }
1044 }
1045
1046 return 0;
1047}
1048
1049/**
1050 * Helper function used only by drm_pending_state_apply, with the same
1051 * guarantees and constraints as that function.
1052 */
1053static int
1054drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
1055 enum drm_state_apply_mode mode)
1056{
1057 struct drm_backend *b = pending_state->backend;
1058 struct drm_output_state *output_state, *tmp;
1059 struct drm_plane *plane;
1060 drmModeAtomicReq *req = drmModeAtomicAlloc();
1061 uint32_t flags;
1062 int ret = 0;
leng.fang13fd3982024-07-03 19:09:58 +08001063 bool mode_changed = false;
1064 bool state_invalid = false;
1065 bool allow_modeset = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001066
1067 if (!req)
1068 return -1;
1069
1070 switch (mode) {
1071 case DRM_STATE_APPLY_SYNC:
1072 flags = 0;
1073 break;
1074 case DRM_STATE_APPLY_ASYNC:
1075 flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
1076 break;
1077 case DRM_STATE_TEST_ONLY:
1078 flags = DRM_MODE_ATOMIC_TEST_ONLY;
1079 break;
1080 }
1081
leng.fang13fd3982024-07-03 19:09:58 +08001082 state_invalid = b->state_invalid;
1083 allow_modeset = b->allow_modeset;
leng.fang3e8a4b52024-07-24 14:51:30 +08001084#ifdef ENABLE_MODE_POLICY
leng.fang13fd3982024-07-03 19:09:58 +08001085 mode_policy_update_modeset(&b->state_invalid, &b->allow_modeset);
leng.fang3e8a4b52024-07-24 14:51:30 +08001086#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001087 if (b->state_invalid) {
1088 struct weston_head *head_base;
1089 struct drm_head *head;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001090 struct drm_crtc *crtc;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001091 uint32_t connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001092 int err;
1093
1094 drm_debug(b, "\t\t[atomic] previous state invalid; "
1095 "starting with fresh state\n");
1096
1097 /* If we need to reset all our state (e.g. because we've
1098 * just started, or just been VT-switched in), explicitly
1099 * disable all the CRTCs and connectors we aren't using. */
leng.fang32af9fc2024-06-13 11:22:15 +08001100#if 0
1101
Daniel Stone4c2fc702019-06-18 11:12:07 +01001102 wl_list_for_each(head_base,
1103 &b->compositor->head_list, compositor_link) {
1104 struct drm_property_info *info;
1105
1106 if (weston_head_is_enabled(head_base))
1107 continue;
1108
1109 head = to_drm_head(head_base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001110 connector_id = head->connector.connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001111
1112 drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
1113 head_base->name);
1114
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001115 info = &head->connector.props[WDRM_CONNECTOR_CRTC_ID];
1116 err = drmModeAtomicAddProperty(req, connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001117 info->prop_id, 0);
1118 drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001119 (unsigned long) connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001120 (unsigned long) info->prop_id,
1121 info->name);
1122 if (err <= 0)
1123 ret = -1;
1124 }
1125
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001126 wl_list_for_each(crtc, &b->crtc_list, link) {
Daniel Stone4c2fc702019-06-18 11:12:07 +01001127 struct drm_property_info *info;
1128 drmModeObjectProperties *props;
1129 uint64_t active;
1130
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001131 /* Ignore CRTCs that are in use */
1132 if (crtc->output)
1133 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001134
1135 /* We can't emit a disable on a CRTC that's already
1136 * off, as the kernel will refuse to generate an event
1137 * for an off->off state and fail the commit.
1138 */
1139 props = drmModeObjectGetProperties(b->drm.fd,
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001140 crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001141 DRM_MODE_OBJECT_CRTC);
1142 if (!props) {
1143 ret = -1;
1144 continue;
1145 }
1146
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001147 info = &crtc->props_crtc[WDRM_CRTC_ACTIVE];
Daniel Stone4c2fc702019-06-18 11:12:07 +01001148 active = drm_property_get_value(info, props, 0);
1149 drmModeFreeObjectProperties(props);
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001150 if (active == 0)
Daniel Stone4c2fc702019-06-18 11:12:07 +01001151 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001152
1153 drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001154 (unsigned long) crtc->crtc_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001155
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001156 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
1157 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001158 }
leng.fang32af9fc2024-06-13 11:22:15 +08001159#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001160
1161 /* Disable all the planes; planes which are being used will
1162 * override this state in the output-state application. */
1163 wl_list_for_each(plane, &b->plane_list, link) {
1164 drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
1165 (unsigned long) plane->plane_id);
1166 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
1167 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
1168 }
1169
leng.fang13fd3982024-07-03 19:09:58 +08001170 if (b->allow_modeset) {
leng.fang32af9fc2024-06-13 11:22:15 +08001171 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
leng.fang13fd3982024-07-03 19:09:58 +08001172 mode_changed = true;
1173 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001174 }
1175
1176 wl_list_for_each(output_state, &pending_state->output_list, link) {
1177 if (output_state->output->virtual)
1178 continue;
1179 if (mode == DRM_STATE_APPLY_SYNC)
1180 assert(output_state->dpms == WESTON_DPMS_OFF);
1181 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
1182 }
1183
1184 if (ret != 0) {
1185 weston_log("atomic: couldn't compile atomic state\n");
1186 goto out;
1187 }
leng.fang32af9fc2024-06-13 11:22:15 +08001188#ifdef ENABLE_DRM_HELP
1189 ret |= help_atomic_req_add_prop(req);
1190#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001191
leng.fang91856072024-06-07 14:12:54 +08001192#ifdef ENABLE_MODE_POLICY
leng.fangb1081a32024-06-25 14:41:37 +08001193 if (mode != DRM_STATE_TEST_ONLY &&
leng.fang13fd3982024-07-03 19:09:58 +08001194 mode_policy_add_prop(req, mode_changed) > 0) {
leng.fangb1081a32024-06-25 14:41:37 +08001195 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
1196 }
leng.fang91856072024-06-07 14:12:54 +08001197#endif
1198
Daniel Stone4c2fc702019-06-18 11:12:07 +01001199 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
1200 drm_debug(b, "[atomic] drmModeAtomicCommit\n");
1201
leng.fang32af9fc2024-06-13 11:22:15 +08001202 drm_update_buffer_commit_result(ret, pending_state);
1203
Daniel Stone4c2fc702019-06-18 11:12:07 +01001204 /* Test commits do not take ownership of the state; return
1205 * without freeing here. */
1206 if (mode == DRM_STATE_TEST_ONLY) {
1207 drmModeAtomicFree(req);
1208 return ret;
1209 }
1210
1211 if (ret != 0) {
leng.fang13fd3982024-07-03 19:09:58 +08001212 weston_log("atomic: couldn't commit new state: %s, flags: %x\n",
1213 strerror(errno), flags);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001214 goto out;
1215 }
1216
1217 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1218 link)
1219 drm_output_assign_state(output_state, mode);
1220
leng.fang13fd3982024-07-03 19:09:58 +08001221 if (mode_changed &&
1222 state_invalid == b->state_invalid &&
1223 allow_modeset == b->allow_modeset) {
1224 b->state_invalid = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001225
leng.fang13fd3982024-07-03 19:09:58 +08001226 if (b->allow_modeset)
1227 b->allow_modeset = false;
1228 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001229 assert(wl_list_empty(&pending_state->output_list));
1230
1231out:
1232 drmModeAtomicFree(req);
1233 drm_pending_state_free(pending_state);
1234 return ret;
1235}
Daniel Stone4c2fc702019-06-18 11:12:07 +01001236
1237/**
1238 * Tests a pending state, to see if the kernel will accept the update as
1239 * constructed.
1240 *
1241 * Using atomic modesetting, the kernel performs the same checks as it would
1242 * on a real commit, returning success or failure without actually modifying
1243 * the running state. It does not return -EBUSY if there are pending updates
1244 * in flight, so states may be tested at any point, however this means a
1245 * state which passed testing may fail on a real commit if the timing is not
1246 * respected (e.g. committing before the previous commit has completed).
1247 *
1248 * Without atomic modesetting, we have no way to check, so we optimistically
1249 * claim it will work.
1250 *
1251 * Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
1252 * function does _not_ take ownership of pending_state, nor does it clear
1253 * state_invalid.
1254 */
1255int
1256drm_pending_state_test(struct drm_pending_state *pending_state)
1257{
Daniel Stone4c2fc702019-06-18 11:12:07 +01001258 struct drm_backend *b = pending_state->backend;
1259
1260 if (b->atomic_modeset)
1261 return drm_pending_state_apply_atomic(pending_state,
1262 DRM_STATE_TEST_ONLY);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001263
1264 /* We have no way to test state before application on the legacy
1265 * modesetting API, so just claim it succeeded. */
1266 return 0;
1267}
1268
1269/**
1270 * Applies all of a pending_state asynchronously: the primary entry point for
1271 * applying KMS state to a device. Updates the state for all outputs in the
1272 * pending_state, as well as disabling any unclaimed outputs.
1273 *
1274 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1275 */
1276int
1277drm_pending_state_apply(struct drm_pending_state *pending_state)
1278{
1279 struct drm_backend *b = pending_state->backend;
1280 struct drm_output_state *output_state, *tmp;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001281 struct drm_crtc *crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001282
Daniel Stone4c2fc702019-06-18 11:12:07 +01001283 if (b->atomic_modeset)
1284 return drm_pending_state_apply_atomic(pending_state,
1285 DRM_STATE_APPLY_ASYNC);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001286
1287 if (b->state_invalid) {
1288 /* If we need to reset all our state (e.g. because we've
1289 * just started, or just been VT-switched in), explicitly
1290 * disable all the CRTCs we aren't using. This also disables
1291 * all connectors on these CRTCs, so we don't need to do that
1292 * separately with the pre-atomic API. */
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001293 wl_list_for_each(crtc, &b->crtc_list, link) {
1294 if (crtc->output)
1295 continue;
1296 drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
1297 NULL, 0, NULL);
1298 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001299 }
1300
1301 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1302 link) {
1303 struct drm_output *output = output_state->output;
1304 int ret;
1305
1306 if (output->virtual) {
1307 drm_output_assign_state(output_state,
1308 DRM_STATE_APPLY_ASYNC);
1309 continue;
1310 }
1311
1312 ret = drm_output_apply_state_legacy(output_state);
1313 if (ret != 0) {
1314 weston_log("Couldn't apply state for output %s\n",
1315 output->base.name);
nerdopolisd2a320d2021-08-23 21:29:42 -04001316 weston_output_repaint_failed(&output->base);
1317 drm_output_state_free(output->state_cur);
1318 output->state_cur = drm_output_state_alloc(output, NULL);
1319 b->state_invalid = true;
1320 if (!b->use_pixman) {
1321 drm_output_fini_egl(output);
1322 drm_output_init_egl(output, b);
1323 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001324 }
1325 }
1326
1327 b->state_invalid = false;
1328
1329 assert(wl_list_empty(&pending_state->output_list));
1330
1331 drm_pending_state_free(pending_state);
1332
1333 return 0;
1334}
1335
1336/**
1337 * The synchronous version of drm_pending_state_apply. May only be used to
1338 * disable outputs. Does so synchronously: the request is guaranteed to have
1339 * completed on return, and the output will not be touched afterwards.
1340 *
1341 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1342 */
1343int
1344drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
1345{
1346 struct drm_backend *b = pending_state->backend;
1347 struct drm_output_state *output_state, *tmp;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001348 struct drm_crtc *crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001349
Daniel Stone4c2fc702019-06-18 11:12:07 +01001350 if (b->atomic_modeset)
1351 return drm_pending_state_apply_atomic(pending_state,
1352 DRM_STATE_APPLY_SYNC);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001353
1354 if (b->state_invalid) {
1355 /* If we need to reset all our state (e.g. because we've
1356 * just started, or just been VT-switched in), explicitly
1357 * disable all the CRTCs we aren't using. This also disables
1358 * all connectors on these CRTCs, so we don't need to do that
1359 * separately with the pre-atomic API. */
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001360 wl_list_for_each(crtc, &b->crtc_list, link) {
1361 if (crtc->output)
1362 continue;
1363 drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
1364 NULL, 0, NULL);
1365 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001366 }
1367
1368 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1369 link) {
1370 int ret;
1371
1372 assert(output_state->dpms == WESTON_DPMS_OFF);
1373 ret = drm_output_apply_state_legacy(output_state);
1374 if (ret != 0) {
1375 weston_log("Couldn't apply state for output %s\n",
1376 output_state->output->base.name);
1377 }
1378 }
1379
1380 b->state_invalid = false;
1381
1382 assert(wl_list_empty(&pending_state->output_list));
1383
1384 drm_pending_state_free(pending_state);
1385
1386 return 0;
1387}
1388
1389void
1390drm_output_update_msc(struct drm_output *output, unsigned int seq)
1391{
1392 uint64_t msc_hi = output->base.msc >> 32;
1393
1394 if (seq < (output->base.msc & 0xffffffff))
1395 msc_hi++;
1396
1397 output->base.msc = (msc_hi << 32) + seq;
1398}
1399
1400static void
1401page_flip_handler(int fd, unsigned int frame,
1402 unsigned int sec, unsigned int usec, void *data)
1403{
1404 struct drm_output *output = data;
1405 struct drm_backend *b = to_drm_backend(output->base.compositor);
1406 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1407 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1408 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1409
1410 drm_output_update_msc(output, frame);
1411
1412 assert(!b->atomic_modeset);
1413 assert(output->page_flip_pending);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001414 output->page_flip_pending = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001415
1416 drm_output_update_complete(output, flags, sec, usec);
1417}
1418
Daniel Stone4c2fc702019-06-18 11:12:07 +01001419static void
1420atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
1421 unsigned int usec, unsigned int crtc_id, void *data)
1422{
1423 struct drm_backend *b = data;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001424 struct drm_crtc *crtc;
1425 struct drm_output *output;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001426 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1427 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1428 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1429
limin.tianc616dad2024-07-15 11:35:38 +00001430 struct timespec ts1, ts2, ts3;
1431 weston_compositor_get_time(&ts1);
1432
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001433 crtc = drm_crtc_find(b, crtc_id);
1434 assert(crtc);
1435
1436 output = crtc->output;
1437
leng.fang32af9fc2024-06-13 11:22:15 +08001438 if (crtc->output_change) {
1439 output = crtc->disable_output;
1440 }
1441
Daniel Stone4c2fc702019-06-18 11:12:07 +01001442 /* During the initial modeset, we can disable CRTCs which we don't
1443 * actually handle during normal operation; this will give us events
1444 * for unknown outputs. Ignore them. */
leng.fang32af9fc2024-06-13 11:22:15 +08001445 if ( (!output || !output->base.enabled) && !crtc->output_change)
Daniel Stone4c2fc702019-06-18 11:12:07 +01001446 return;
1447
1448 drm_output_update_msc(output, frame);
limin.tianc616dad2024-07-15 11:35:38 +00001449 weston_compositor_get_time(&ts2);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001450
leng.fang32af9fc2024-06-13 11:22:15 +08001451 drm_debug(b, "[atomic][CRTC:%u] flip processing started output_change:%d\n",
1452 crtc_id,crtc->output_change );
1453 if ( b->atomic_modeset && output->atomic_complete_pending) {
1454 //assert(b->atomic_modeset);
1455 //assert(output->atomic_complete_pending);
1456 output->atomic_complete_pending = false;
1457 drm_output_update_complete(output, flags, sec, usec);
1458 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001459
leng.fang32af9fc2024-06-13 11:22:15 +08001460 crtc->output_change = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001461 drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
limin.tianc616dad2024-07-15 11:35:38 +00001462
1463 weston_compositor_get_time(&ts3);
1464 if ( (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)) > 10000 )
1465 weston_log("\n %s %d take:(%lld %lld %lld)\n",
1466 __FUNCTION__,__LINE__,
1467 (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)),
1468 (timespec_to_usec(&ts2) - timespec_to_usec(&ts1)),
1469 (timespec_to_usec(&ts3) - timespec_to_usec(&ts2))
1470 );
leng.fang32af9fc2024-06-13 11:22:15 +08001471 atomic_flip_handler_time(b);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001472}
Daniel Stone4c2fc702019-06-18 11:12:07 +01001473
1474int
1475on_drm_input(int fd, uint32_t mask, void *data)
1476{
Daniel Stone4c2fc702019-06-18 11:12:07 +01001477 struct drm_backend *b = data;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001478 drmEventContext evctx;
limin.tianc616dad2024-07-15 11:35:38 +00001479 struct timespec ts1, ts2, ts3;
1480 weston_compositor_get_time(&ts1);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001481
1482 memset(&evctx, 0, sizeof evctx);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001483 evctx.version = 3;
1484 if (b->atomic_modeset)
1485 evctx.page_flip_handler2 = atomic_flip_handler;
1486 else
Daniel Stone4c2fc702019-06-18 11:12:07 +01001487 evctx.page_flip_handler = page_flip_handler;
limin.tianc616dad2024-07-15 11:35:38 +00001488
1489 weston_compositor_get_time(&ts2);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001490 drmHandleEvent(fd, &evctx);
limin.tianc616dad2024-07-15 11:35:38 +00001491 weston_compositor_get_time(&ts3);
1492 if ( (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)) > 10000 )
1493 weston_log("\n %s %d %lld %lld,take:(%lld %lld %lld)\n",
1494 __FUNCTION__,__LINE__, timespec_to_usec(&ts1), timespec_to_usec(&ts3),
1495 (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)),
1496 (timespec_to_usec(&ts2) - timespec_to_usec(&ts1)),
1497 (timespec_to_usec(&ts3) - timespec_to_usec(&ts2))
1498 );
Daniel Stone4c2fc702019-06-18 11:12:07 +01001499
1500 return 1;
1501}
1502
1503int
1504init_kms_caps(struct drm_backend *b)
1505{
1506 uint64_t cap;
1507 int ret;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001508
1509 weston_log("using %s\n", b->drm.filename);
1510
1511 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Pekka Paalanenf48277b2021-05-10 11:44:57 +03001512 if (ret != 0 || cap != 1) {
1513 weston_log("Error: kernel DRM KMS does not support DRM_CAP_TIMESTAMP_MONOTONIC.\n");
1514 return -1;
1515 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001516
Pekka Paalanenf48277b2021-05-10 11:44:57 +03001517 if (weston_compositor_set_presentation_clock(b->compositor, CLOCK_MONOTONIC) < 0) {
1518 weston_log("Error: failed to set presentation clock to CLOCK_MONOTONIC.\n");
Daniel Stone4c2fc702019-06-18 11:12:07 +01001519 return -1;
1520 }
1521
1522 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
1523 if (ret == 0)
1524 b->cursor_width = cap;
1525 else
1526 b->cursor_width = 64;
1527
1528 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1529 if (ret == 0)
1530 b->cursor_height = cap;
1531 else
1532 b->cursor_height = 64;
1533
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001534 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1535 if (ret) {
1536 weston_log("Error: drm card doesn't support universal planes!\n");
1537 return -1;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001538 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001539
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001540 if (!getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone4c2fc702019-06-18 11:12:07 +01001541 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
1542 if (ret != 0)
1543 cap = 0;
1544 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
1545 b->atomic_modeset = ((ret == 0) && (cap == 1));
1546 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001547 weston_log("DRM: %s atomic modesetting\n",
1548 b->atomic_modeset ? "supports" : "does not support");
1549
Stefan Agner465ab2c2020-06-17 23:36:44 +02001550 if (!getenv("WESTON_DISABLE_GBM_MODIFIERS")) {
1551 ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
1552 if (ret == 0)
1553 b->fb_modifiers = cap;
1554 }
1555 weston_log("DRM: %s GBM modifiers\n",
1556 b->fb_modifiers ? "supports" : "does not support");
Daniel Stone4c2fc702019-06-18 11:12:07 +01001557
Leandro Ribeiro96bef052020-09-09 15:23:49 -03001558 drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
1559
Daniel Stone4c2fc702019-06-18 11:12:07 +01001560 /*
1561 * KMS support for hardware planes cannot properly synchronize
1562 * without nuclear page flip. Without nuclear/atomic, hw plane
1563 * and cursor plane updates would either tear or cause extra
1564 * waits for vblanks which means dropping the compositor framerate
1565 * to a fraction. For cursors, it's not so bad, so they are
1566 * enabled.
1567 */
1568 if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001569 b->sprites_are_broken = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001570
1571 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
1572 b->aspect_ratio_supported = (ret == 0);
1573 weston_log("DRM: %s picture aspect ratio\n",
1574 b->aspect_ratio_supported ? "supports" : "does not support");
1575
1576 return 0;
1577}