blob: 86e9d1e05452f763b726bc00b2134e4bcc0b1702 [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" },
chen.wang1f06854b2024-09-26 11:26:04 +000080 [WDRM_PLANE_VIDEO_ROTATION] = { .name = "rotation" },
Daniel Stone4c2fc702019-06-18 11:12:07 +010081};
82
83struct drm_property_enum_info dpms_state_enums[] = {
84 [WDRM_DPMS_STATE_OFF] = {
85 .name = "Off",
86 },
87 [WDRM_DPMS_STATE_ON] = {
88 .name = "On",
89 },
90 [WDRM_DPMS_STATE_STANDBY] = {
91 .name = "Standby",
92 },
93 [WDRM_DPMS_STATE_SUSPEND] = {
94 .name = "Suspend",
95 },
96};
97
Ankit Nautiyala344fe32019-05-14 18:36:08 +053098struct drm_property_enum_info content_protection_enums[] = {
99 [WDRM_CONTENT_PROTECTION_UNDESIRED] = {
100 .name = "Undesired",
101 },
102 [WDRM_CONTENT_PROTECTION_DESIRED] = {
103 .name = "Desired",
104 },
105 [WDRM_CONTENT_PROTECTION_ENABLED] = {
106 .name = "Enabled",
107 },
108};
109
110struct drm_property_enum_info hdcp_content_type_enums[] = {
111 [WDRM_HDCP_CONTENT_TYPE0] = {
112 .name = "HDCP Type0",
113 },
114 [WDRM_HDCP_CONTENT_TYPE1] = {
115 .name = "HDCP Type1",
116 },
117};
118
Lucas Stach72e7a1e2019-11-25 23:31:57 +0000119struct drm_property_enum_info panel_orientation_enums[] = {
120 [WDRM_PANEL_ORIENTATION_NORMAL] = { .name = "Normal", },
121 [WDRM_PANEL_ORIENTATION_UPSIDE_DOWN] = { .name = "Upside Down", },
122 [WDRM_PANEL_ORIENTATION_LEFT_SIDE_UP] = { .name = "Left Side Up", },
123 [WDRM_PANEL_ORIENTATION_RIGHT_SIDE_UP] = { .name = "Right Side Up", },
124};
125
Daniel Stone4c2fc702019-06-18 11:12:07 +0100126const struct drm_property_info connector_props[] = {
127 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
128 [WDRM_CONNECTOR_DPMS] = {
129 .name = "DPMS",
130 .enum_values = dpms_state_enums,
131 .num_enum_values = WDRM_DPMS_STATE__COUNT,
132 },
133 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
134 [WDRM_CONNECTOR_NON_DESKTOP] = { .name = "non-desktop", },
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530135 [WDRM_CONNECTOR_CONTENT_PROTECTION] = {
leng.fangdbaf6fa2024-06-20 19:31:04 +0800136 .name = "ContentProtection",
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530137 .enum_values = content_protection_enums,
138 .num_enum_values = WDRM_CONTENT_PROTECTION__COUNT,
139 },
140 [WDRM_CONNECTOR_HDCP_CONTENT_TYPE] = {
141 .name = "HDCP Content Type",
142 .enum_values = hdcp_content_type_enums,
143 .num_enum_values = WDRM_HDCP_CONTENT_TYPE__COUNT,
144 },
Lucas Stach72e7a1e2019-11-25 23:31:57 +0000145 [WDRM_CONNECTOR_PANEL_ORIENTATION] = {
146 .name = "panel orientation",
147 .enum_values = panel_orientation_enums,
148 .num_enum_values = WDRM_PANEL_ORIENTATION__COUNT,
149 },
Daniel Stone4c2fc702019-06-18 11:12:07 +0100150};
151
152const struct drm_property_info crtc_props[] = {
153 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
154 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
155};
156
157
158/**
159 * Mode for drm_pending_state_apply and co.
160 */
161enum drm_state_apply_mode {
162 DRM_STATE_APPLY_SYNC, /**< state fully processed */
163 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
164 DRM_STATE_TEST_ONLY, /**< test if the state can be applied */
165};
166
167/**
168 * Get the current value of a KMS property
169 *
170 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
171 * for the target property, return the current value of that property,
172 * with an optional default. If the property is a KMS enum type, the return
173 * value will be translated into the appropriate internal enum.
174 *
175 * If the property is not present, the default value will be returned.
176 *
177 * @param info Internal structure for property to look up
178 * @param props Raw KMS properties for the target object
179 * @param def Value to return if property is not found
180 */
181uint64_t
182drm_property_get_value(struct drm_property_info *info,
183 const drmModeObjectProperties *props,
184 uint64_t def)
185{
186 unsigned int i;
187
188 if (info->prop_id == 0)
189 return def;
190
191 for (i = 0; i < props->count_props; i++) {
192 unsigned int j;
193
194 if (props->props[i] != info->prop_id)
195 continue;
196
197 /* Simple (non-enum) types can return the value directly */
198 if (info->num_enum_values == 0)
199 return props->prop_values[i];
200
201 /* Map from raw value to enum value */
202 for (j = 0; j < info->num_enum_values; j++) {
203 if (!info->enum_values[j].valid)
204 continue;
205 if (info->enum_values[j].value != props->prop_values[i])
206 continue;
207
208 return j;
209 }
210
211 /* We don't have a mapping for this enum; return default. */
212 break;
213 }
214
215 return def;
216}
217
218/**
Marius Vlad1accffe2019-11-01 12:00:09 +0200219 * Get the current range values of a KMS property
220 *
221 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
222 * for the target property, return the current range values of that property,
223 *
224 * If the property is not present, or there's no it is not a prop range then
225 * NULL will be returned.
226 *
227 * @param info Internal structure for property to look up
228 * @param props Raw KMS properties for the target object
229 */
230uint64_t *
231drm_property_get_range_values(struct drm_property_info *info,
232 const drmModeObjectProperties *props)
233{
234 unsigned int i;
235
236 if (info->prop_id == 0)
237 return NULL;
238
239 for (i = 0; i < props->count_props; i++) {
240
241 if (props->props[i] != info->prop_id)
242 continue;
243
244 if (!(info->flags & DRM_MODE_PROP_RANGE) &&
245 !(info->flags & DRM_MODE_PROP_SIGNED_RANGE))
246 continue;
247
248 return info->range_values;
249 }
250
251 return NULL;
252}
253
254/**
Daniel Stone4c2fc702019-06-18 11:12:07 +0100255 * Cache DRM property values
256 *
257 * Update a per-object array of drm_property_info structures, given the
258 * DRM properties of the object.
259 *
260 * Call this every time an object newly appears (note that only connectors
261 * can be hotplugged), the first time it is seen, or when its status changes
262 * in a way which invalidates the potential property values (currently, the
263 * only case for this is connector hotplug).
264 *
265 * This updates the property IDs and enum values within the drm_property_info
266 * array.
267 *
268 * DRM property enum values are dynamic at runtime; the user must query the
269 * property to find out the desired runtime value for a requested string
270 * name. Using the 'type' field on planes as an example, there is no single
271 * hardcoded constant for primary plane types; instead, the property must be
272 * queried at runtime to find the value associated with the string "Primary".
273 *
274 * This helper queries and caches the enum values, to allow us to use a set
275 * of compile-time-constant enums portably across various implementations.
276 * The values given in enum_names are searched for, and stored in the
277 * same-indexed field of the map array.
278 *
279 * @param b DRM backend object
280 * @param src DRM property info array to source from
281 * @param info DRM property info array to copy into
282 * @param num_infos Number of entries in the source array
283 * @param props DRM object properties for the object
284 */
285void
286drm_property_info_populate(struct drm_backend *b,
287 const struct drm_property_info *src,
288 struct drm_property_info *info,
289 unsigned int num_infos,
290 drmModeObjectProperties *props)
291{
292 drmModePropertyRes *prop;
293 unsigned i, j;
294
295 for (i = 0; i < num_infos; i++) {
296 unsigned int j;
297
298 info[i].name = src[i].name;
299 info[i].prop_id = 0;
300 info[i].num_enum_values = src[i].num_enum_values;
301
302 if (src[i].num_enum_values == 0)
303 continue;
304
305 info[i].enum_values =
306 malloc(src[i].num_enum_values *
307 sizeof(*info[i].enum_values));
308 assert(info[i].enum_values);
309 for (j = 0; j < info[i].num_enum_values; j++) {
310 info[i].enum_values[j].name = src[i].enum_values[j].name;
311 info[i].enum_values[j].valid = false;
312 }
313 }
314
315 for (i = 0; i < props->count_props; i++) {
316 unsigned int k;
317
318 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
319 if (!prop)
320 continue;
321
322 for (j = 0; j < num_infos; j++) {
323 if (!strcmp(prop->name, info[j].name))
324 break;
325 }
326
327 /* We don't know/care about this property. */
328 if (j == num_infos) {
329#ifdef DEBUG
330 weston_log("DRM debug: unrecognized property %u '%s'\n",
331 prop->prop_id, prop->name);
332#endif
333 drmModeFreeProperty(prop);
334 continue;
335 }
336
337 if (info[j].num_enum_values == 0 &&
338 (prop->flags & DRM_MODE_PROP_ENUM)) {
339 weston_log("DRM: expected property %s to not be an"
340 " enum, but it is; ignoring\n", prop->name);
341 drmModeFreeProperty(prop);
342 continue;
343 }
344
345 info[j].prop_id = props->props[i];
Marius Vlad1accffe2019-11-01 12:00:09 +0200346 info[j].flags = prop->flags;
347
348 if (prop->flags & DRM_MODE_PROP_RANGE ||
349 prop->flags & DRM_MODE_PROP_SIGNED_RANGE) {
350 info[j].num_range_values = prop->count_values;
351 for (int i = 0; i < prop->count_values; i++)
352 info[j].range_values[i] = prop->values[i];
353 }
354
Daniel Stone4c2fc702019-06-18 11:12:07 +0100355
356 if (info[j].num_enum_values == 0) {
357 drmModeFreeProperty(prop);
358 continue;
359 }
360
361 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
362 weston_log("DRM: expected property %s to be an enum,"
363 " but it is not; ignoring\n", prop->name);
364 drmModeFreeProperty(prop);
365 info[j].prop_id = 0;
366 continue;
367 }
368
369 for (k = 0; k < info[j].num_enum_values; k++) {
370 int l;
371
372 for (l = 0; l < prop->count_enums; l++) {
373 if (!strcmp(prop->enums[l].name,
374 info[j].enum_values[k].name))
375 break;
376 }
377
378 if (l == prop->count_enums)
379 continue;
380
381 info[j].enum_values[k].valid = true;
382 info[j].enum_values[k].value = prop->enums[l].value;
383 }
384
385 drmModeFreeProperty(prop);
386 }
387
388#ifdef DEBUG
389 for (i = 0; i < num_infos; i++) {
390 if (info[i].prop_id == 0)
391 weston_log("DRM warning: property '%s' missing\n",
392 info[i].name);
393 }
394#endif
395}
396
397/**
398 * Free DRM property information
399 *
400 * Frees all memory associated with a DRM property info array and zeroes
401 * it out, leaving it usable for a further drm_property_info_update() or
402 * drm_property_info_free().
403 *
404 * @param info DRM property info array
405 * @param num_props Number of entries in array to free
406 */
407void
408drm_property_info_free(struct drm_property_info *info, int num_props)
409{
410 int i;
411
412 for (i = 0; i < num_props; i++)
413 free(info[i].enum_values);
414
415 memset(info, 0, sizeof(*info) * num_props);
416}
417
Daniel Stone4c2fc702019-06-18 11:12:07 +0100418static inline uint32_t *
419formats_ptr(struct drm_format_modifier_blob *blob)
420{
421 return (uint32_t *)(((char *)blob) + blob->formats_offset);
422}
423
424static inline struct drm_format_modifier *
425modifiers_ptr(struct drm_format_modifier_blob *blob)
426{
427 return (struct drm_format_modifier *)
428 (((char *)blob) + blob->modifiers_offset);
429}
Daniel Stone4c2fc702019-06-18 11:12:07 +0100430
431/**
432 * Populates the plane's formats array, using either the IN_FORMATS blob
433 * property (if available), or the plane's format list if not.
434 */
435int
436drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
Stefan Agner465ab2c2020-06-17 23:36:44 +0200437 const drmModeObjectProperties *props,
438 const bool use_modifiers)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100439{
Scott Anderson74663092021-02-01 15:46:33 -0300440 unsigned i, j;
441 drmModePropertyBlobRes *blob = NULL;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100442 struct drm_format_modifier_blob *fmt_mod_blob;
443 struct drm_format_modifier *blob_modifiers;
444 uint32_t *blob_formats;
445 uint32_t blob_id;
Scott Anderson74663092021-02-01 15:46:33 -0300446 struct weston_drm_format *fmt;
447 int ret = 0;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100448
Stefan Agner465ab2c2020-06-17 23:36:44 +0200449 if (!use_modifiers)
450 goto fallback;
451
Daniel Stone4c2fc702019-06-18 11:12:07 +0100452 blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
453 props,
454 0);
455 if (blob_id == 0)
456 goto fallback;
457
458 blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
459 if (!blob)
460 goto fallback;
461
462 fmt_mod_blob = blob->data;
463 blob_formats = formats_ptr(fmt_mod_blob);
464 blob_modifiers = modifiers_ptr(fmt_mod_blob);
465
Scott Anderson74663092021-02-01 15:46:33 -0300466 assert(kplane->count_formats == fmt_mod_blob->count_formats);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100467
468 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
Scott Anderson74663092021-02-01 15:46:33 -0300469 fmt = weston_drm_format_array_add_format(&plane->formats,
470 blob_formats[i]);
471 if (!fmt) {
472 ret = -1;
473 goto out;
474 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100475
476 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
477 struct drm_format_modifier *mod = &blob_modifiers[j];
478
479 if ((i < mod->offset) || (i > mod->offset + 63))
480 continue;
481 if (!(mod->formats & (1 << (i - mod->offset))))
482 continue;
483
Scott Anderson74663092021-02-01 15:46:33 -0300484 ret = weston_drm_format_add_modifier(fmt, mod->modifier);
485 if (ret < 0)
486 goto out;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100487 }
488
Leandro Ribeiro98101e82021-04-21 11:46:35 -0300489 if (fmt->modifiers.size == 0)
490 weston_drm_format_array_remove_latest_format(&plane->formats);
leng.fang32af9fc2024-06-13 11:22:15 +0800491
492 if (fmt->format == DRM_FORMAT_NV12 ||
493 fmt->format == DRM_FORMAT_NV21)
494 plane->is_video_plane = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100495 }
496
Scott Anderson74663092021-02-01 15:46:33 -0300497out:
Daniel Stone4c2fc702019-06-18 11:12:07 +0100498 drmModeFreePropertyBlob(blob);
Scott Anderson74663092021-02-01 15:46:33 -0300499 return ret;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100500
501fallback:
Daniel Stone4c2fc702019-06-18 11:12:07 +0100502 /* No IN_FORMATS blob available, so just use the old. */
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900503 for (i = 0; i < kplane->count_formats; i++) {
Scott Anderson74663092021-02-01 15:46:33 -0300504 fmt = weston_drm_format_array_add_format(&plane->formats,
505 kplane->formats[i]);
506 if (!fmt)
507 return -1;
Leandro Ribeiro567cc922021-04-21 11:44:53 -0300508 ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_INVALID);
Scott Anderson74663092021-02-01 15:46:33 -0300509 if (ret < 0)
510 return -1;
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900511 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100512 return 0;
513}
514
515void
516drm_output_set_gamma(struct weston_output *output_base,
517 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
518{
519 int rc;
520 struct drm_output *output = to_drm_output(output_base);
521 struct drm_backend *backend =
522 to_drm_backend(output->base.compositor);
523
524 /* check */
525 if (output_base->gamma_size != size)
526 return;
527
528 rc = drmModeCrtcSetGamma(backend->drm.fd,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300529 output->crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100530 size, r, g, b);
531 if (rc)
532 weston_log("set gamma failed: %s\n", strerror(errno));
533}
534
535/**
536 * Mark an output state as current on the output, i.e. it has been
537 * submitted to the kernel. The mode argument determines whether this
538 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
539 * or asynchronously (in which case we wait for events to complete).
540 */
541static void
542drm_output_assign_state(struct drm_output_state *state,
543 enum drm_state_apply_mode mode)
544{
545 struct drm_output *output = state->output;
546 struct drm_backend *b = to_drm_backend(output->base.compositor);
547 struct drm_plane_state *plane_state;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530548 struct drm_head *head;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100549
550 assert(!output->state_last);
551
552 if (mode == DRM_STATE_APPLY_ASYNC)
553 output->state_last = output->state_cur;
554 else
555 drm_output_state_free(output->state_cur);
556
557 wl_list_remove(&state->link);
558 wl_list_init(&state->link);
559 state->pending_state = NULL;
560
561 output->state_cur = state;
562
563 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300564 drm_debug(b, "\t[CRTC:%u] setting pending flip\n",
565 output->crtc->crtc_id);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100566 output->atomic_complete_pending = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100567 }
568
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530569 if (b->atomic_modeset &&
570 state->protection == WESTON_HDCP_DISABLE)
571 wl_list_for_each(head, &output->base.head_list, base.output_link)
572 weston_head_set_content_protection_status(&head->base,
573 WESTON_HDCP_DISABLE);
574
Daniel Stone4c2fc702019-06-18 11:12:07 +0100575 /* Replace state_cur on each affected plane with the new state, being
576 * careful to dispose of orphaned (but only orphaned) previous state.
577 * If the previous state is not orphaned (still has an output_state
578 * attached), it will be disposed of by freeing the output_state. */
579 wl_list_for_each(plane_state, &state->plane_list, link) {
580 struct drm_plane *plane = plane_state->plane;
581
582 if (plane->state_cur && !plane->state_cur->output_state)
583 drm_plane_state_free(plane->state_cur, true);
584 plane->state_cur = plane_state;
585
586 if (mode != DRM_STATE_APPLY_ASYNC) {
587 plane_state->complete = true;
588 continue;
589 }
590
591 if (b->atomic_modeset)
592 continue;
593
594 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
595 if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100596 output->page_flip_pending = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100597 }
598}
599
600static void
601drm_output_set_cursor(struct drm_output_state *output_state)
602{
603 struct drm_output *output = output_state->output;
604 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300605 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100606 struct drm_plane *plane = output->cursor_plane;
607 struct drm_plane_state *state;
Stefan Agner974390a2019-07-08 00:42:05 +0200608 uint32_t handle;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100609
610 if (!plane)
611 return;
612
613 state = drm_output_state_get_existing_plane(output_state, plane);
614 if (!state)
615 return;
616
617 if (!state->fb) {
618 pixman_region32_fini(&plane->base.damage);
619 pixman_region32_init(&plane->base.damage);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300620 drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100621 return;
622 }
623
624 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
625 assert(!plane->state_cur->output || plane->state_cur->output == output);
626
Stefan Agner974390a2019-07-08 00:42:05 +0200627 handle = output->gbm_cursor_handle[output->current_cursor];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100628 if (plane->state_cur->fb != state->fb) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300629 if (drmModeSetCursor(b->drm.fd, crtc->crtc_id, handle,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100630 b->cursor_width, b->cursor_height)) {
631 weston_log("failed to set cursor: %s\n",
632 strerror(errno));
633 goto err;
634 }
635 }
636
637 pixman_region32_fini(&plane->base.damage);
638 pixman_region32_init(&plane->base.damage);
639
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300640 if (drmModeMoveCursor(b->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100641 state->dest_x, state->dest_y)) {
642 weston_log("failed to move cursor: %s\n", strerror(errno));
643 goto err;
644 }
645
646 return;
647
648err:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100649 b->cursors_are_broken = true;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300650 drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100651}
652
653static int
654drm_output_apply_state_legacy(struct drm_output_state *state)
655{
656 struct drm_output *output = state->output;
657 struct drm_backend *backend = to_drm_backend(output->base.compositor);
658 struct drm_plane *scanout_plane = output->scanout_plane;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300659 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100660 struct drm_property_info *dpms_prop;
661 struct drm_plane_state *scanout_state;
662 struct drm_mode *mode;
663 struct drm_head *head;
664 const struct pixel_format_info *pinfo = NULL;
665 uint32_t connectors[MAX_CLONED_CONNECTORS];
666 int n_conn = 0;
667 struct timespec now;
668 int ret = 0;
669
670 wl_list_for_each(head, &output->base.head_list, base.output_link) {
671 assert(n_conn < MAX_CLONED_CONNECTORS);
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300672 connectors[n_conn++] = head->connector.connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100673 }
674
675 /* If disable_planes is set then assign_planes() wasn't
676 * called for this render, so we could still have a stale
677 * cursor plane set up.
678 */
679 if (output->base.disable_planes) {
Alexandros Frantzis10937fe2021-06-14 13:09:44 +0300680 drm_output_set_cursor_view(output, NULL);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100681 if (output->cursor_plane) {
682 output->cursor_plane->base.x = INT32_MIN;
683 output->cursor_plane->base.y = INT32_MIN;
684 }
685 }
686
687 if (state->dpms != WESTON_DPMS_ON) {
688 if (output->cursor_plane) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300689 ret = drmModeSetCursor(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100690 0, 0, 0);
691 if (ret)
692 weston_log("drmModeSetCursor failed disable: %s\n",
693 strerror(errno));
694 }
695
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300696 ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, 0, 0, 0,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100697 NULL, 0, NULL);
698 if (ret)
699 weston_log("drmModeSetCrtc failed disabling: %s\n",
700 strerror(errno));
701
702 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
703 weston_compositor_read_presentation_clock(output->base.compositor, &now);
704 drm_output_update_complete(output,
705 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
706 now.tv_sec, now.tv_nsec / 1000);
707
708 return 0;
709 }
710
711 scanout_state =
712 drm_output_state_get_existing_plane(state, scanout_plane);
713
714 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
715 * legacy PageFlip API doesn't allow us to do clipping either. */
716 assert(scanout_state->src_x == 0);
717 assert(scanout_state->src_y == 0);
718 assert(scanout_state->src_w ==
719 (unsigned) (output->base.current_mode->width << 16));
720 assert(scanout_state->src_h ==
721 (unsigned) (output->base.current_mode->height << 16));
722 assert(scanout_state->dest_x == 0);
723 assert(scanout_state->dest_y == 0);
724 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
725 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
726 /* The legacy SetCrtc API doesn't support fences */
727 assert(scanout_state->in_fence_fd == -1);
728
729 mode = to_drm_mode(output->base.current_mode);
730 if (backend->state_invalid ||
731 !scanout_plane->state_cur->fb ||
732 scanout_plane->state_cur->fb->strides[0] !=
733 scanout_state->fb->strides[0]) {
734
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300735 ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100736 scanout_state->fb->fb_id,
737 0, 0,
738 connectors, n_conn,
739 &mode->mode_info);
740 if (ret) {
741 weston_log("set mode failed: %s\n", strerror(errno));
742 goto err;
743 }
744 }
745
746 pinfo = scanout_state->fb->format;
747 drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300748 crtc->crtc_id, scanout_state->plane->plane_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100749 pinfo ? pinfo->drm_format_name : "UNKNOWN");
750
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300751 if (drmModePageFlip(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100752 scanout_state->fb->fb_id,
753 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
754 weston_log("queueing pageflip failed: %s\n", strerror(errno));
755 goto err;
756 }
757
758 assert(!output->page_flip_pending);
759
760 if (output->pageflip_timer)
761 wl_event_source_timer_update(output->pageflip_timer,
762 backend->pageflip_timeout);
763
764 drm_output_set_cursor(state);
765
766 if (state->dpms != output->state_cur->dpms) {
767 wl_list_for_each(head, &output->base.head_list, base.output_link) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300768 dpms_prop = &head->connector.props[WDRM_CONNECTOR_DPMS];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100769 if (dpms_prop->prop_id == 0)
770 continue;
771
772 ret = drmModeConnectorSetProperty(backend->drm.fd,
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300773 head->connector.connector_id,
774 dpms_prop->prop_id,
775 state->dpms);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100776 if (ret) {
777 weston_log("DRM: DPMS: failed property set for %s\n",
778 head->base.name);
779 }
780 }
781 }
782
783 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
784
785 return 0;
786
787err:
Alexandros Frantzis10937fe2021-06-14 13:09:44 +0300788 drm_output_set_cursor_view(output, NULL);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100789 drm_output_state_free(state);
790 return -1;
791}
792
Daniel Stone4c2fc702019-06-18 11:12:07 +0100793static int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300794crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100795 enum wdrm_crtc_property prop, uint64_t val)
796{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300797 struct drm_property_info *info = &crtc->props_crtc[prop];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100798 int ret;
799
800 if (info->prop_id == 0)
801 return -1;
802
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300803 ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100804 val);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300805 drm_debug(crtc->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
806 (unsigned long) crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100807 (unsigned long) info->prop_id, info->name,
808 (unsigned long long) val, (unsigned long long) val);
809 return (ret <= 0) ? -1 : 0;
810}
811
812static int
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300813connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100814 enum wdrm_connector_property prop, uint64_t val)
815{
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300816 struct drm_property_info *info = &connector->props[prop];
817 uint32_t connector_id = connector->connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100818 int ret;
819
820 if (info->prop_id == 0)
821 return -1;
822
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300823 ret = drmModeAtomicAddProperty(req, connector_id, info->prop_id, val);
824 drm_debug(connector->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
825 (unsigned long) connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100826 (unsigned long) info->prop_id, info->name,
827 (unsigned long long) val, (unsigned long long) val);
828 return (ret <= 0) ? -1 : 0;
829}
830
831static int
832plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
833 enum wdrm_plane_property prop, uint64_t val)
834{
835 struct drm_property_info *info = &plane->props[prop];
836 int ret;
837
838 if (info->prop_id == 0)
839 return -1;
840
841 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
842 val);
843 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
844 (unsigned long) plane->plane_id,
845 (unsigned long) info->prop_id, info->name,
846 (unsigned long long) val, (unsigned long long) val);
847 return (ret <= 0) ? -1 : 0;
848}
849
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530850static bool
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300851drm_connector_has_prop(struct drm_connector *connector,
852 enum wdrm_connector_property prop)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530853{
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300854 if (connector->props[prop].prop_id != 0)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530855 return true;
856
857 return false;
858}
859
860/*
861 * This function converts the protection requests from weston_hdcp_protection
862 * corresponding drm values. These values can be set in "Content Protection"
863 * & "HDCP Content Type" connector properties.
864 */
865static void
866get_drm_protection_from_weston(enum weston_hdcp_protection weston_protection,
867 enum wdrm_content_protection_state *drm_protection,
868 enum wdrm_hdcp_content_type *drm_cp_type)
869{
870
871 switch (weston_protection) {
872 case WESTON_HDCP_DISABLE:
873 *drm_protection = WDRM_CONTENT_PROTECTION_UNDESIRED;
874 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
875 break;
876 case WESTON_HDCP_ENABLE_TYPE_0:
877 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
878 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
879 break;
880 case WESTON_HDCP_ENABLE_TYPE_1:
881 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
882 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE1;
883 break;
884 default:
885 assert(0 && "bad weston_hdcp_protection");
886 }
887}
888
889static void
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300890drm_connector_set_hdcp_property(struct drm_connector *connector,
891 enum weston_hdcp_protection protection,
892 drmModeAtomicReq *req)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530893{
894 int ret;
895 enum wdrm_content_protection_state drm_protection;
896 enum wdrm_hdcp_content_type drm_cp_type;
897 struct drm_property_enum_info *enum_info;
898 uint64_t prop_val;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300899 struct drm_property_info *props = connector->props;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530900
901 get_drm_protection_from_weston(protection, &drm_protection,
902 &drm_cp_type);
903
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300904 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_CONTENT_PROTECTION))
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530905 return;
906
907 /*
908 * Content-type property is not exposed for platforms not supporting
909 * HDCP2.2, therefore, type-1 cannot be supported. The type-0 content
910 * still can be supported if the content-protection property is exposed.
911 */
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300912 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE) &&
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530913 drm_cp_type != WDRM_HDCP_CONTENT_TYPE0)
914 return;
915
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300916 enum_info = props[WDRM_CONNECTOR_CONTENT_PROTECTION].enum_values;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530917 prop_val = enum_info[drm_protection].value;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300918 ret = connector_add_prop(req, connector,
919 WDRM_CONNECTOR_CONTENT_PROTECTION, prop_val);
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530920 assert(ret == 0);
921
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300922 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE))
Ankit Nautiyalfc2c1802019-08-30 19:40:46 +0530923 return;
924
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300925 enum_info = props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE].enum_values;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530926 prop_val = enum_info[drm_cp_type].value;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300927 ret = connector_add_prop(req, connector,
928 WDRM_CONNECTOR_HDCP_CONTENT_TYPE, prop_val);
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530929 assert(ret == 0);
930}
931
Daniel Stone4c2fc702019-06-18 11:12:07 +0100932static int
933drm_output_apply_state_atomic(struct drm_output_state *state,
934 drmModeAtomicReq *req,
935 uint32_t *flags)
936{
937 struct drm_output *output = state->output;
938 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300939 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100940 struct drm_plane_state *plane_state;
941 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
942 struct drm_head *head;
943 int ret = 0;
944
945 drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
946 (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
947 (unsigned long) output->base.id, output->base.name);
948
949 if (state->dpms != output->state_cur->dpms) {
950 drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
951 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
952 }
953
954 if (state->dpms == WESTON_DPMS_ON) {
955 ret = drm_mode_ensure_blob(b, current_mode);
956 if (ret != 0)
957 return ret;
958
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300959 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100960 current_mode->blob_id);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300961 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 1);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100962
963 /* No need for the DPMS property, since it is implicit in
964 * routing and CRTC activity. */
965 wl_list_for_each(head, &output->base.head_list, base.output_link) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300966 ret |= connector_add_prop(req, &head->connector,
967 WDRM_CONNECTOR_CRTC_ID,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300968 crtc->crtc_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100969 }
970 } else {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300971 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
972 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100973
974 /* No need for the DPMS property, since it is implicit in
975 * routing and CRTC activity. */
976 wl_list_for_each(head, &output->base.head_list, base.output_link)
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300977 ret |= connector_add_prop(req, &head->connector,
978 WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100979 }
980
Daniel Stone4c2fc702019-06-18 11:12:07 +0100981 if (ret != 0) {
982 weston_log("couldn't set atomic CRTC/connector state\n");
983 return ret;
984 }
chen.wang1fdc0f562024-09-04 07:57:16 +0000985 if ( !(*flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
986 drm_update_default_video_zorder(state);
987 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100988 wl_list_for_each(plane_state, &state->plane_list, link) {
989 struct drm_plane *plane = plane_state->plane;
990 const struct pixel_format_info *pinfo = NULL;
leng.fangc0af1fa2024-08-13 17:54:42 +0800991 int dest_x, dest_y;
992 uint32_t dest_w, dest_h;
leng.fang32af9fc2024-06-13 11:22:15 +0800993 if ( !plane_state->fb )
994 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100995
996 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
997 plane_state->fb ? plane_state->fb->fb_id : 0);
leng.fang32af9fc2024-06-13 11:22:15 +0800998
999 drm_update_video_plane_info(plane_state, flags);
leng.fangc0af1fa2024-08-13 17:54:42 +08001000 drm_update_plane_info(plane_state, *flags, &dest_x, &dest_y, &dest_w, &dest_h);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001001 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001002 plane_state->fb ? crtc->crtc_id : 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001003 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
1004 plane_state->src_x);
1005 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
1006 plane_state->src_y);
1007 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
1008 plane_state->src_w);
1009 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
1010 plane_state->src_h);
1011 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
leng.fangc0af1fa2024-08-13 17:54:42 +08001012 dest_x);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001013 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
leng.fangc0af1fa2024-08-13 17:54:42 +08001014 dest_y);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001015 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
leng.fangc0af1fa2024-08-13 17:54:42 +08001016 dest_w);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001017 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
leng.fangc0af1fa2024-08-13 17:54:42 +08001018 dest_h);
Scott Anderson15c603c2020-06-02 17:39:43 +12001019 if (plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS].prop_id != 0)
1020 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS,
1021 plane_state->damage_blob_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001022
chen.wang1f06854b2024-09-26 11:26:04 +00001023 if (plane->is_video_plane ) {
1024 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] video plane, video_transform:%d\n",
1025 (unsigned long) plane->plane_id,
1026 plane_state->video_transform);
1027
1028 ret |= plane_add_prop(req, plane, WDRM_PLANE_VIDEO_ROTATION,
1029 1 << plane_state->video_transform);
1030 }
1031
Daniel Stone4c2fc702019-06-18 11:12:07 +01001032 if (plane_state->fb && plane_state->fb->format)
1033 pinfo = plane_state->fb->format;
1034
1035 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
1036 (unsigned long) plane->plane_id,
1037 pinfo ? pinfo->drm_format_name : "UNKNOWN");
1038
1039 if (plane_state->in_fence_fd >= 0) {
1040 ret |= plane_add_prop(req, plane,
1041 WDRM_PLANE_IN_FENCE_FD,
1042 plane_state->in_fence_fd);
1043 }
leng.fang32af9fc2024-06-13 11:22:15 +08001044#ifdef USE_DEFAULT_Z_ORDER
1045 //use drm default palne z-order
limin.tian85cd2462024-08-12 08:04:12 +00001046 if (!plane_state->plane->is_video_plane) {
1047 plane_state->zpos = DEFAULT_OSD_PLANE_ZPOS + plane_state->plane->plane_idx;
1048 ret |= plane_add_prop(req, plane,
1049 WDRM_PLANE_ZPOS,
1050 plane_state->zpos);
1051 }
chen.wang1fdc0f562024-09-04 07:57:16 +00001052 //video palne z-order
1053 if (plane_state->plane->is_video_plane) {
1054 ret |= plane_add_prop(req, plane,
1055 WDRM_PLANE_ZPOS,
1056 plane_state->video_zpos);
1057 }
leng.fang32af9fc2024-06-13 11:22:15 +08001058#else
Marius Vladcdd6fa22019-08-29 20:42:00 +03001059 /* do note, that 'invented' zpos values are set as immutable */
1060 if (plane_state->zpos != DRM_PLANE_ZPOS_INVALID_PLANE &&
1061 plane_state->plane->zpos_min != plane_state->plane->zpos_max)
1062 ret |= plane_add_prop(req, plane,
1063 WDRM_PLANE_ZPOS,
1064 plane_state->zpos);
leng.fang32af9fc2024-06-13 11:22:15 +08001065#endif
Marius Vladcdd6fa22019-08-29 20:42:00 +03001066
Daniel Stone4c2fc702019-06-18 11:12:07 +01001067 if (ret != 0) {
1068 weston_log("couldn't set plane state\n");
1069 return ret;
1070 }
1071 }
1072
1073 return 0;
1074}
1075
1076/**
1077 * Helper function used only by drm_pending_state_apply, with the same
1078 * guarantees and constraints as that function.
1079 */
1080static int
1081drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
1082 enum drm_state_apply_mode mode)
1083{
1084 struct drm_backend *b = pending_state->backend;
1085 struct drm_output_state *output_state, *tmp;
1086 struct drm_plane *plane;
1087 drmModeAtomicReq *req = drmModeAtomicAlloc();
1088 uint32_t flags;
1089 int ret = 0;
leng.fang13fd3982024-07-03 19:09:58 +08001090 bool mode_changed = false;
1091 bool state_invalid = false;
1092 bool allow_modeset = false;
leng.fang69a93e32024-08-08 16:31:01 +08001093 int possible = 0;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001094
1095 if (!req)
1096 return -1;
1097
1098 switch (mode) {
1099 case DRM_STATE_APPLY_SYNC:
1100 flags = 0;
1101 break;
1102 case DRM_STATE_APPLY_ASYNC:
1103 flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
1104 break;
1105 case DRM_STATE_TEST_ONLY:
1106 flags = DRM_MODE_ATOMIC_TEST_ONLY;
1107 break;
1108 }
1109
leng.fang13fd3982024-07-03 19:09:58 +08001110 state_invalid = b->state_invalid;
1111 allow_modeset = b->allow_modeset;
leng.fang3e8a4b52024-07-24 14:51:30 +08001112#ifdef ENABLE_MODE_POLICY
leng.fang69a93e32024-08-08 16:31:01 +08001113 mode_policy_update_modeset(&b->state_invalid, &b->allow_modeset, &possible);
leng.fang3e8a4b52024-07-24 14:51:30 +08001114#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001115 if (b->state_invalid) {
1116 struct weston_head *head_base;
1117 struct drm_head *head;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001118 struct drm_crtc *crtc;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001119 uint32_t connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001120 int err;
1121
1122 drm_debug(b, "\t\t[atomic] previous state invalid; "
1123 "starting with fresh state\n");
1124
1125 /* If we need to reset all our state (e.g. because we've
1126 * just started, or just been VT-switched in), explicitly
1127 * disable all the CRTCs and connectors we aren't using. */
leng.fang32af9fc2024-06-13 11:22:15 +08001128#if 0
1129
Daniel Stone4c2fc702019-06-18 11:12:07 +01001130 wl_list_for_each(head_base,
1131 &b->compositor->head_list, compositor_link) {
1132 struct drm_property_info *info;
1133
1134 if (weston_head_is_enabled(head_base))
1135 continue;
1136
1137 head = to_drm_head(head_base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001138 connector_id = head->connector.connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001139
1140 drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
1141 head_base->name);
1142
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001143 info = &head->connector.props[WDRM_CONNECTOR_CRTC_ID];
1144 err = drmModeAtomicAddProperty(req, connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001145 info->prop_id, 0);
1146 drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001147 (unsigned long) connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001148 (unsigned long) info->prop_id,
1149 info->name);
1150 if (err <= 0)
1151 ret = -1;
1152 }
1153
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001154 wl_list_for_each(crtc, &b->crtc_list, link) {
Daniel Stone4c2fc702019-06-18 11:12:07 +01001155 struct drm_property_info *info;
1156 drmModeObjectProperties *props;
1157 uint64_t active;
1158
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001159 /* Ignore CRTCs that are in use */
1160 if (crtc->output)
1161 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001162
1163 /* We can't emit a disable on a CRTC that's already
1164 * off, as the kernel will refuse to generate an event
1165 * for an off->off state and fail the commit.
1166 */
1167 props = drmModeObjectGetProperties(b->drm.fd,
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001168 crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001169 DRM_MODE_OBJECT_CRTC);
1170 if (!props) {
1171 ret = -1;
1172 continue;
1173 }
1174
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001175 info = &crtc->props_crtc[WDRM_CRTC_ACTIVE];
Daniel Stone4c2fc702019-06-18 11:12:07 +01001176 active = drm_property_get_value(info, props, 0);
1177 drmModeFreeObjectProperties(props);
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001178 if (active == 0)
Daniel Stone4c2fc702019-06-18 11:12:07 +01001179 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001180
1181 drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001182 (unsigned long) crtc->crtc_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001183
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001184 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
1185 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001186 }
leng.fang32af9fc2024-06-13 11:22:15 +08001187#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001188
1189 /* Disable all the planes; planes which are being used will
1190 * override this state in the output-state application. */
1191 wl_list_for_each(plane, &b->plane_list, link) {
1192 drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
1193 (unsigned long) plane->plane_id);
leng.fang69a93e32024-08-08 16:31:01 +08001194 if (possible && (possible & plane->possible_crtcs) == 0)
1195 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001196 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
1197 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
1198 }
1199
leng.fang13fd3982024-07-03 19:09:58 +08001200 if (b->allow_modeset) {
leng.fang32af9fc2024-06-13 11:22:15 +08001201 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
leng.fang13fd3982024-07-03 19:09:58 +08001202 mode_changed = true;
1203 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001204 }
1205
1206 wl_list_for_each(output_state, &pending_state->output_list, link) {
1207 if (output_state->output->virtual)
1208 continue;
1209 if (mode == DRM_STATE_APPLY_SYNC)
1210 assert(output_state->dpms == WESTON_DPMS_OFF);
1211 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
1212 }
1213
1214 if (ret != 0) {
1215 weston_log("atomic: couldn't compile atomic state\n");
1216 goto out;
1217 }
leng.fang32af9fc2024-06-13 11:22:15 +08001218#ifdef ENABLE_DRM_HELP
1219 ret |= help_atomic_req_add_prop(req);
1220#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001221
leng.fang91856072024-06-07 14:12:54 +08001222#ifdef ENABLE_MODE_POLICY
leng.fangb1081a32024-06-25 14:41:37 +08001223 if (mode != DRM_STATE_TEST_ONLY &&
leng.fang13fd3982024-07-03 19:09:58 +08001224 mode_policy_add_prop(req, mode_changed) > 0) {
leng.fangb1081a32024-06-25 14:41:37 +08001225 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
1226 }
leng.fang91856072024-06-07 14:12:54 +08001227#endif
1228
Daniel Stone4c2fc702019-06-18 11:12:07 +01001229 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
1230 drm_debug(b, "[atomic] drmModeAtomicCommit\n");
1231
leng.fang32af9fc2024-06-13 11:22:15 +08001232 drm_update_buffer_commit_result(ret, pending_state);
1233
Daniel Stone4c2fc702019-06-18 11:12:07 +01001234 /* Test commits do not take ownership of the state; return
1235 * without freeing here. */
1236 if (mode == DRM_STATE_TEST_ONLY) {
1237 drmModeAtomicFree(req);
1238 return ret;
1239 }
1240
1241 if (ret != 0) {
leng.fang13fd3982024-07-03 19:09:58 +08001242 weston_log("atomic: couldn't commit new state: %s, flags: %x\n",
1243 strerror(errno), flags);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001244 goto out;
1245 }
1246
1247 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1248 link)
1249 drm_output_assign_state(output_state, mode);
1250
leng.fang13fd3982024-07-03 19:09:58 +08001251 if (mode_changed &&
1252 state_invalid == b->state_invalid &&
1253 allow_modeset == b->allow_modeset) {
1254 b->state_invalid = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001255
leng.fang13fd3982024-07-03 19:09:58 +08001256 if (b->allow_modeset)
1257 b->allow_modeset = false;
1258 }
leng.fang69a93e32024-08-08 16:31:01 +08001259
1260 if (b->state_invalid && !allow_modeset &&
1261 state_invalid == b->state_invalid)
1262 b->state_invalid = false;
1263
Daniel Stone4c2fc702019-06-18 11:12:07 +01001264 assert(wl_list_empty(&pending_state->output_list));
1265
1266out:
1267 drmModeAtomicFree(req);
1268 drm_pending_state_free(pending_state);
1269 return ret;
1270}
Daniel Stone4c2fc702019-06-18 11:12:07 +01001271
1272/**
1273 * Tests a pending state, to see if the kernel will accept the update as
1274 * constructed.
1275 *
1276 * Using atomic modesetting, the kernel performs the same checks as it would
1277 * on a real commit, returning success or failure without actually modifying
1278 * the running state. It does not return -EBUSY if there are pending updates
1279 * in flight, so states may be tested at any point, however this means a
1280 * state which passed testing may fail on a real commit if the timing is not
1281 * respected (e.g. committing before the previous commit has completed).
1282 *
1283 * Without atomic modesetting, we have no way to check, so we optimistically
1284 * claim it will work.
1285 *
1286 * Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
1287 * function does _not_ take ownership of pending_state, nor does it clear
1288 * state_invalid.
1289 */
1290int
1291drm_pending_state_test(struct drm_pending_state *pending_state)
1292{
Daniel Stone4c2fc702019-06-18 11:12:07 +01001293 struct drm_backend *b = pending_state->backend;
1294
1295 if (b->atomic_modeset)
1296 return drm_pending_state_apply_atomic(pending_state,
1297 DRM_STATE_TEST_ONLY);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001298
1299 /* We have no way to test state before application on the legacy
1300 * modesetting API, so just claim it succeeded. */
1301 return 0;
1302}
1303
1304/**
1305 * Applies all of a pending_state asynchronously: the primary entry point for
1306 * applying KMS state to a device. Updates the state for all outputs in the
1307 * pending_state, as well as disabling any unclaimed outputs.
1308 *
1309 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1310 */
1311int
1312drm_pending_state_apply(struct drm_pending_state *pending_state)
1313{
1314 struct drm_backend *b = pending_state->backend;
1315 struct drm_output_state *output_state, *tmp;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001316 struct drm_crtc *crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001317
Daniel Stone4c2fc702019-06-18 11:12:07 +01001318 if (b->atomic_modeset)
1319 return drm_pending_state_apply_atomic(pending_state,
1320 DRM_STATE_APPLY_ASYNC);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001321
1322 if (b->state_invalid) {
1323 /* If we need to reset all our state (e.g. because we've
1324 * just started, or just been VT-switched in), explicitly
1325 * disable all the CRTCs we aren't using. This also disables
1326 * all connectors on these CRTCs, so we don't need to do that
1327 * separately with the pre-atomic API. */
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001328 wl_list_for_each(crtc, &b->crtc_list, link) {
1329 if (crtc->output)
1330 continue;
1331 drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
1332 NULL, 0, NULL);
1333 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001334 }
1335
1336 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1337 link) {
1338 struct drm_output *output = output_state->output;
1339 int ret;
1340
1341 if (output->virtual) {
1342 drm_output_assign_state(output_state,
1343 DRM_STATE_APPLY_ASYNC);
1344 continue;
1345 }
1346
1347 ret = drm_output_apply_state_legacy(output_state);
1348 if (ret != 0) {
1349 weston_log("Couldn't apply state for output %s\n",
1350 output->base.name);
nerdopolisd2a320d2021-08-23 21:29:42 -04001351 weston_output_repaint_failed(&output->base);
1352 drm_output_state_free(output->state_cur);
1353 output->state_cur = drm_output_state_alloc(output, NULL);
1354 b->state_invalid = true;
1355 if (!b->use_pixman) {
1356 drm_output_fini_egl(output);
1357 drm_output_init_egl(output, b);
1358 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001359 }
1360 }
1361
1362 b->state_invalid = false;
1363
1364 assert(wl_list_empty(&pending_state->output_list));
1365
1366 drm_pending_state_free(pending_state);
1367
1368 return 0;
1369}
1370
1371/**
1372 * The synchronous version of drm_pending_state_apply. May only be used to
1373 * disable outputs. Does so synchronously: the request is guaranteed to have
1374 * completed on return, and the output will not be touched afterwards.
1375 *
1376 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1377 */
1378int
1379drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
1380{
1381 struct drm_backend *b = pending_state->backend;
1382 struct drm_output_state *output_state, *tmp;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001383 struct drm_crtc *crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001384
Daniel Stone4c2fc702019-06-18 11:12:07 +01001385 if (b->atomic_modeset)
1386 return drm_pending_state_apply_atomic(pending_state,
1387 DRM_STATE_APPLY_SYNC);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001388
1389 if (b->state_invalid) {
1390 /* If we need to reset all our state (e.g. because we've
1391 * just started, or just been VT-switched in), explicitly
1392 * disable all the CRTCs we aren't using. This also disables
1393 * all connectors on these CRTCs, so we don't need to do that
1394 * separately with the pre-atomic API. */
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001395 wl_list_for_each(crtc, &b->crtc_list, link) {
1396 if (crtc->output)
1397 continue;
1398 drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
1399 NULL, 0, NULL);
1400 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001401 }
1402
1403 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1404 link) {
1405 int ret;
1406
1407 assert(output_state->dpms == WESTON_DPMS_OFF);
1408 ret = drm_output_apply_state_legacy(output_state);
1409 if (ret != 0) {
1410 weston_log("Couldn't apply state for output %s\n",
1411 output_state->output->base.name);
1412 }
1413 }
1414
1415 b->state_invalid = false;
1416
1417 assert(wl_list_empty(&pending_state->output_list));
1418
1419 drm_pending_state_free(pending_state);
1420
1421 return 0;
1422}
1423
1424void
1425drm_output_update_msc(struct drm_output *output, unsigned int seq)
1426{
1427 uint64_t msc_hi = output->base.msc >> 32;
1428
1429 if (seq < (output->base.msc & 0xffffffff))
1430 msc_hi++;
1431
1432 output->base.msc = (msc_hi << 32) + seq;
1433}
1434
1435static void
1436page_flip_handler(int fd, unsigned int frame,
1437 unsigned int sec, unsigned int usec, void *data)
1438{
1439 struct drm_output *output = data;
1440 struct drm_backend *b = to_drm_backend(output->base.compositor);
1441 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1442 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1443 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1444
1445 drm_output_update_msc(output, frame);
1446
1447 assert(!b->atomic_modeset);
1448 assert(output->page_flip_pending);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001449 output->page_flip_pending = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001450
1451 drm_output_update_complete(output, flags, sec, usec);
1452}
1453
Daniel Stone4c2fc702019-06-18 11:12:07 +01001454static void
1455atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
1456 unsigned int usec, unsigned int crtc_id, void *data)
1457{
1458 struct drm_backend *b = data;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001459 struct drm_crtc *crtc;
1460 struct drm_output *output;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001461 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1462 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1463 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1464
limin.tianc616dad2024-07-15 11:35:38 +00001465 struct timespec ts1, ts2, ts3;
1466 weston_compositor_get_time(&ts1);
1467
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001468 crtc = drm_crtc_find(b, crtc_id);
1469 assert(crtc);
1470
1471 output = crtc->output;
1472
leng.fang32af9fc2024-06-13 11:22:15 +08001473 if (crtc->output_change) {
1474 output = crtc->disable_output;
1475 }
1476
Daniel Stone4c2fc702019-06-18 11:12:07 +01001477 /* During the initial modeset, we can disable CRTCs which we don't
1478 * actually handle during normal operation; this will give us events
1479 * for unknown outputs. Ignore them. */
leng.fang32af9fc2024-06-13 11:22:15 +08001480 if ( (!output || !output->base.enabled) && !crtc->output_change)
Daniel Stone4c2fc702019-06-18 11:12:07 +01001481 return;
1482
1483 drm_output_update_msc(output, frame);
limin.tianc616dad2024-07-15 11:35:38 +00001484 weston_compositor_get_time(&ts2);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001485
leng.fang32af9fc2024-06-13 11:22:15 +08001486 drm_debug(b, "[atomic][CRTC:%u] flip processing started output_change:%d\n",
1487 crtc_id,crtc->output_change );
1488 if ( b->atomic_modeset && output->atomic_complete_pending) {
1489 //assert(b->atomic_modeset);
1490 //assert(output->atomic_complete_pending);
1491 output->atomic_complete_pending = false;
1492 drm_output_update_complete(output, flags, sec, usec);
1493 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001494
leng.fang32af9fc2024-06-13 11:22:15 +08001495 crtc->output_change = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001496 drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
limin.tianc616dad2024-07-15 11:35:38 +00001497
1498 weston_compositor_get_time(&ts3);
1499 if ( (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)) > 10000 )
1500 weston_log("\n %s %d take:(%lld %lld %lld)\n",
1501 __FUNCTION__,__LINE__,
1502 (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)),
1503 (timespec_to_usec(&ts2) - timespec_to_usec(&ts1)),
1504 (timespec_to_usec(&ts3) - timespec_to_usec(&ts2))
1505 );
leng.fang32af9fc2024-06-13 11:22:15 +08001506 atomic_flip_handler_time(b);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001507}
Daniel Stone4c2fc702019-06-18 11:12:07 +01001508
1509int
1510on_drm_input(int fd, uint32_t mask, void *data)
1511{
Daniel Stone4c2fc702019-06-18 11:12:07 +01001512 struct drm_backend *b = data;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001513 drmEventContext evctx;
limin.tianc616dad2024-07-15 11:35:38 +00001514 struct timespec ts1, ts2, ts3;
1515 weston_compositor_get_time(&ts1);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001516
1517 memset(&evctx, 0, sizeof evctx);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001518 evctx.version = 3;
1519 if (b->atomic_modeset)
1520 evctx.page_flip_handler2 = atomic_flip_handler;
1521 else
Daniel Stone4c2fc702019-06-18 11:12:07 +01001522 evctx.page_flip_handler = page_flip_handler;
limin.tianc616dad2024-07-15 11:35:38 +00001523
1524 weston_compositor_get_time(&ts2);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001525 drmHandleEvent(fd, &evctx);
limin.tianc616dad2024-07-15 11:35:38 +00001526 weston_compositor_get_time(&ts3);
1527 if ( (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)) > 10000 )
1528 weston_log("\n %s %d %lld %lld,take:(%lld %lld %lld)\n",
1529 __FUNCTION__,__LINE__, timespec_to_usec(&ts1), timespec_to_usec(&ts3),
1530 (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)),
1531 (timespec_to_usec(&ts2) - timespec_to_usec(&ts1)),
1532 (timespec_to_usec(&ts3) - timespec_to_usec(&ts2))
1533 );
Daniel Stone4c2fc702019-06-18 11:12:07 +01001534
1535 return 1;
1536}
1537
1538int
1539init_kms_caps(struct drm_backend *b)
1540{
1541 uint64_t cap;
1542 int ret;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001543
1544 weston_log("using %s\n", b->drm.filename);
1545
1546 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Pekka Paalanenf48277b2021-05-10 11:44:57 +03001547 if (ret != 0 || cap != 1) {
1548 weston_log("Error: kernel DRM KMS does not support DRM_CAP_TIMESTAMP_MONOTONIC.\n");
1549 return -1;
1550 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001551
Pekka Paalanenf48277b2021-05-10 11:44:57 +03001552 if (weston_compositor_set_presentation_clock(b->compositor, CLOCK_MONOTONIC) < 0) {
1553 weston_log("Error: failed to set presentation clock to CLOCK_MONOTONIC.\n");
Daniel Stone4c2fc702019-06-18 11:12:07 +01001554 return -1;
1555 }
1556
1557 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
1558 if (ret == 0)
1559 b->cursor_width = cap;
1560 else
1561 b->cursor_width = 64;
1562
1563 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1564 if (ret == 0)
1565 b->cursor_height = cap;
1566 else
1567 b->cursor_height = 64;
1568
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001569 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1570 if (ret) {
1571 weston_log("Error: drm card doesn't support universal planes!\n");
1572 return -1;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001573 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001574
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001575 if (!getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone4c2fc702019-06-18 11:12:07 +01001576 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
1577 if (ret != 0)
1578 cap = 0;
1579 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
1580 b->atomic_modeset = ((ret == 0) && (cap == 1));
1581 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001582 weston_log("DRM: %s atomic modesetting\n",
1583 b->atomic_modeset ? "supports" : "does not support");
1584
Stefan Agner465ab2c2020-06-17 23:36:44 +02001585 if (!getenv("WESTON_DISABLE_GBM_MODIFIERS")) {
1586 ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
1587 if (ret == 0)
1588 b->fb_modifiers = cap;
1589 }
1590 weston_log("DRM: %s GBM modifiers\n",
1591 b->fb_modifiers ? "supports" : "does not support");
Daniel Stone4c2fc702019-06-18 11:12:07 +01001592
Leandro Ribeiro96bef052020-09-09 15:23:49 -03001593 drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
1594
Daniel Stone4c2fc702019-06-18 11:12:07 +01001595 /*
1596 * KMS support for hardware planes cannot properly synchronize
1597 * without nuclear page flip. Without nuclear/atomic, hw plane
1598 * and cursor plane updates would either tear or cause extra
1599 * waits for vblanks which means dropping the compositor framerate
1600 * to a fraction. For cursors, it's not so bad, so they are
1601 * enabled.
1602 */
1603 if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001604 b->sprites_are_broken = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001605
1606 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
1607 b->aspect_ratio_supported = (ret == 0);
1608 weston_log("DRM: %s picture aspect ratio\n",
1609 b->aspect_ratio_supported ? "supports" : "does not support");
1610
1611 return 0;
1612}