blob: 1accda394d0bf40ece92d1fccb0bc3213c9ddbe3 [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" },
leng.fanga0f20922024-10-11 17:23:59 +080081 [WDRM_PLANE_ALPHA] = { .name = "alpha" },
Daniel Stone4c2fc702019-06-18 11:12:07 +010082};
83
84struct drm_property_enum_info dpms_state_enums[] = {
85 [WDRM_DPMS_STATE_OFF] = {
86 .name = "Off",
87 },
88 [WDRM_DPMS_STATE_ON] = {
89 .name = "On",
90 },
91 [WDRM_DPMS_STATE_STANDBY] = {
92 .name = "Standby",
93 },
94 [WDRM_DPMS_STATE_SUSPEND] = {
95 .name = "Suspend",
96 },
97};
98
Ankit Nautiyala344fe32019-05-14 18:36:08 +053099struct drm_property_enum_info content_protection_enums[] = {
100 [WDRM_CONTENT_PROTECTION_UNDESIRED] = {
101 .name = "Undesired",
102 },
103 [WDRM_CONTENT_PROTECTION_DESIRED] = {
104 .name = "Desired",
105 },
106 [WDRM_CONTENT_PROTECTION_ENABLED] = {
107 .name = "Enabled",
108 },
109};
110
111struct drm_property_enum_info hdcp_content_type_enums[] = {
112 [WDRM_HDCP_CONTENT_TYPE0] = {
113 .name = "HDCP Type0",
114 },
115 [WDRM_HDCP_CONTENT_TYPE1] = {
116 .name = "HDCP Type1",
117 },
118};
119
Lucas Stach72e7a1e2019-11-25 23:31:57 +0000120struct drm_property_enum_info panel_orientation_enums[] = {
121 [WDRM_PANEL_ORIENTATION_NORMAL] = { .name = "Normal", },
122 [WDRM_PANEL_ORIENTATION_UPSIDE_DOWN] = { .name = "Upside Down", },
123 [WDRM_PANEL_ORIENTATION_LEFT_SIDE_UP] = { .name = "Left Side Up", },
124 [WDRM_PANEL_ORIENTATION_RIGHT_SIDE_UP] = { .name = "Right Side Up", },
125};
126
Daniel Stone4c2fc702019-06-18 11:12:07 +0100127const struct drm_property_info connector_props[] = {
128 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
129 [WDRM_CONNECTOR_DPMS] = {
130 .name = "DPMS",
131 .enum_values = dpms_state_enums,
132 .num_enum_values = WDRM_DPMS_STATE__COUNT,
133 },
134 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
135 [WDRM_CONNECTOR_NON_DESKTOP] = { .name = "non-desktop", },
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530136 [WDRM_CONNECTOR_CONTENT_PROTECTION] = {
leng.fangdbaf6fa2024-06-20 19:31:04 +0800137 .name = "ContentProtection",
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530138 .enum_values = content_protection_enums,
139 .num_enum_values = WDRM_CONTENT_PROTECTION__COUNT,
140 },
141 [WDRM_CONNECTOR_HDCP_CONTENT_TYPE] = {
142 .name = "HDCP Content Type",
143 .enum_values = hdcp_content_type_enums,
144 .num_enum_values = WDRM_HDCP_CONTENT_TYPE__COUNT,
145 },
Lucas Stach72e7a1e2019-11-25 23:31:57 +0000146 [WDRM_CONNECTOR_PANEL_ORIENTATION] = {
147 .name = "panel orientation",
148 .enum_values = panel_orientation_enums,
149 .num_enum_values = WDRM_PANEL_ORIENTATION__COUNT,
150 },
Daniel Stone4c2fc702019-06-18 11:12:07 +0100151};
152
153const struct drm_property_info crtc_props[] = {
154 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
155 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
156};
157
158
159/**
160 * Mode for drm_pending_state_apply and co.
161 */
162enum drm_state_apply_mode {
163 DRM_STATE_APPLY_SYNC, /**< state fully processed */
164 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
165 DRM_STATE_TEST_ONLY, /**< test if the state can be applied */
166};
167
168/**
169 * Get the current value of a KMS property
170 *
171 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
172 * for the target property, return the current value of that property,
173 * with an optional default. If the property is a KMS enum type, the return
174 * value will be translated into the appropriate internal enum.
175 *
176 * If the property is not present, the default value will be returned.
177 *
178 * @param info Internal structure for property to look up
179 * @param props Raw KMS properties for the target object
180 * @param def Value to return if property is not found
181 */
182uint64_t
183drm_property_get_value(struct drm_property_info *info,
184 const drmModeObjectProperties *props,
185 uint64_t def)
186{
187 unsigned int i;
188
189 if (info->prop_id == 0)
190 return def;
191
192 for (i = 0; i < props->count_props; i++) {
193 unsigned int j;
194
195 if (props->props[i] != info->prop_id)
196 continue;
197
198 /* Simple (non-enum) types can return the value directly */
199 if (info->num_enum_values == 0)
200 return props->prop_values[i];
201
202 /* Map from raw value to enum value */
203 for (j = 0; j < info->num_enum_values; j++) {
204 if (!info->enum_values[j].valid)
205 continue;
206 if (info->enum_values[j].value != props->prop_values[i])
207 continue;
208
209 return j;
210 }
211
212 /* We don't have a mapping for this enum; return default. */
213 break;
214 }
215
216 return def;
217}
218
219/**
Marius Vlad1accffe2019-11-01 12:00:09 +0200220 * Get the current range values of a KMS property
221 *
222 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
223 * for the target property, return the current range values of that property,
224 *
225 * If the property is not present, or there's no it is not a prop range then
226 * NULL will be returned.
227 *
228 * @param info Internal structure for property to look up
229 * @param props Raw KMS properties for the target object
230 */
231uint64_t *
232drm_property_get_range_values(struct drm_property_info *info,
233 const drmModeObjectProperties *props)
234{
235 unsigned int i;
236
237 if (info->prop_id == 0)
238 return NULL;
239
240 for (i = 0; i < props->count_props; i++) {
241
242 if (props->props[i] != info->prop_id)
243 continue;
244
245 if (!(info->flags & DRM_MODE_PROP_RANGE) &&
246 !(info->flags & DRM_MODE_PROP_SIGNED_RANGE))
247 continue;
248
249 return info->range_values;
250 }
251
252 return NULL;
253}
254
255/**
Daniel Stone4c2fc702019-06-18 11:12:07 +0100256 * Cache DRM property values
257 *
258 * Update a per-object array of drm_property_info structures, given the
259 * DRM properties of the object.
260 *
261 * Call this every time an object newly appears (note that only connectors
262 * can be hotplugged), the first time it is seen, or when its status changes
263 * in a way which invalidates the potential property values (currently, the
264 * only case for this is connector hotplug).
265 *
266 * This updates the property IDs and enum values within the drm_property_info
267 * array.
268 *
269 * DRM property enum values are dynamic at runtime; the user must query the
270 * property to find out the desired runtime value for a requested string
271 * name. Using the 'type' field on planes as an example, there is no single
272 * hardcoded constant for primary plane types; instead, the property must be
273 * queried at runtime to find the value associated with the string "Primary".
274 *
275 * This helper queries and caches the enum values, to allow us to use a set
276 * of compile-time-constant enums portably across various implementations.
277 * The values given in enum_names are searched for, and stored in the
278 * same-indexed field of the map array.
279 *
280 * @param b DRM backend object
281 * @param src DRM property info array to source from
282 * @param info DRM property info array to copy into
283 * @param num_infos Number of entries in the source array
284 * @param props DRM object properties for the object
285 */
286void
287drm_property_info_populate(struct drm_backend *b,
288 const struct drm_property_info *src,
289 struct drm_property_info *info,
290 unsigned int num_infos,
291 drmModeObjectProperties *props)
292{
293 drmModePropertyRes *prop;
294 unsigned i, j;
295
296 for (i = 0; i < num_infos; i++) {
297 unsigned int j;
298
299 info[i].name = src[i].name;
300 info[i].prop_id = 0;
301 info[i].num_enum_values = src[i].num_enum_values;
302
303 if (src[i].num_enum_values == 0)
304 continue;
305
306 info[i].enum_values =
307 malloc(src[i].num_enum_values *
308 sizeof(*info[i].enum_values));
309 assert(info[i].enum_values);
310 for (j = 0; j < info[i].num_enum_values; j++) {
311 info[i].enum_values[j].name = src[i].enum_values[j].name;
312 info[i].enum_values[j].valid = false;
313 }
314 }
315
316 for (i = 0; i < props->count_props; i++) {
317 unsigned int k;
318
319 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
320 if (!prop)
321 continue;
322
323 for (j = 0; j < num_infos; j++) {
324 if (!strcmp(prop->name, info[j].name))
325 break;
326 }
327
328 /* We don't know/care about this property. */
329 if (j == num_infos) {
330#ifdef DEBUG
331 weston_log("DRM debug: unrecognized property %u '%s'\n",
332 prop->prop_id, prop->name);
333#endif
334 drmModeFreeProperty(prop);
335 continue;
336 }
337
338 if (info[j].num_enum_values == 0 &&
339 (prop->flags & DRM_MODE_PROP_ENUM)) {
340 weston_log("DRM: expected property %s to not be an"
341 " enum, but it is; ignoring\n", prop->name);
342 drmModeFreeProperty(prop);
343 continue;
344 }
345
346 info[j].prop_id = props->props[i];
Marius Vlad1accffe2019-11-01 12:00:09 +0200347 info[j].flags = prop->flags;
348
349 if (prop->flags & DRM_MODE_PROP_RANGE ||
350 prop->flags & DRM_MODE_PROP_SIGNED_RANGE) {
351 info[j].num_range_values = prop->count_values;
352 for (int i = 0; i < prop->count_values; i++)
353 info[j].range_values[i] = prop->values[i];
354 }
355
Daniel Stone4c2fc702019-06-18 11:12:07 +0100356
357 if (info[j].num_enum_values == 0) {
358 drmModeFreeProperty(prop);
359 continue;
360 }
361
362 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
363 weston_log("DRM: expected property %s to be an enum,"
364 " but it is not; ignoring\n", prop->name);
365 drmModeFreeProperty(prop);
366 info[j].prop_id = 0;
367 continue;
368 }
369
370 for (k = 0; k < info[j].num_enum_values; k++) {
371 int l;
372
373 for (l = 0; l < prop->count_enums; l++) {
374 if (!strcmp(prop->enums[l].name,
375 info[j].enum_values[k].name))
376 break;
377 }
378
379 if (l == prop->count_enums)
380 continue;
381
382 info[j].enum_values[k].valid = true;
383 info[j].enum_values[k].value = prop->enums[l].value;
384 }
385
386 drmModeFreeProperty(prop);
387 }
388
389#ifdef DEBUG
390 for (i = 0; i < num_infos; i++) {
391 if (info[i].prop_id == 0)
392 weston_log("DRM warning: property '%s' missing\n",
393 info[i].name);
394 }
395#endif
396}
397
398/**
399 * Free DRM property information
400 *
401 * Frees all memory associated with a DRM property info array and zeroes
402 * it out, leaving it usable for a further drm_property_info_update() or
403 * drm_property_info_free().
404 *
405 * @param info DRM property info array
406 * @param num_props Number of entries in array to free
407 */
408void
409drm_property_info_free(struct drm_property_info *info, int num_props)
410{
411 int i;
412
413 for (i = 0; i < num_props; i++)
414 free(info[i].enum_values);
415
416 memset(info, 0, sizeof(*info) * num_props);
417}
418
Daniel Stone4c2fc702019-06-18 11:12:07 +0100419static inline uint32_t *
420formats_ptr(struct drm_format_modifier_blob *blob)
421{
422 return (uint32_t *)(((char *)blob) + blob->formats_offset);
423}
424
425static inline struct drm_format_modifier *
426modifiers_ptr(struct drm_format_modifier_blob *blob)
427{
428 return (struct drm_format_modifier *)
429 (((char *)blob) + blob->modifiers_offset);
430}
Daniel Stone4c2fc702019-06-18 11:12:07 +0100431
432/**
433 * Populates the plane's formats array, using either the IN_FORMATS blob
434 * property (if available), or the plane's format list if not.
435 */
436int
437drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
Stefan Agner465ab2c2020-06-17 23:36:44 +0200438 const drmModeObjectProperties *props,
439 const bool use_modifiers)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100440{
Scott Anderson74663092021-02-01 15:46:33 -0300441 unsigned i, j;
442 drmModePropertyBlobRes *blob = NULL;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100443 struct drm_format_modifier_blob *fmt_mod_blob;
444 struct drm_format_modifier *blob_modifiers;
445 uint32_t *blob_formats;
446 uint32_t blob_id;
Scott Anderson74663092021-02-01 15:46:33 -0300447 struct weston_drm_format *fmt;
448 int ret = 0;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100449
Stefan Agner465ab2c2020-06-17 23:36:44 +0200450 if (!use_modifiers)
451 goto fallback;
452
Daniel Stone4c2fc702019-06-18 11:12:07 +0100453 blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
454 props,
455 0);
456 if (blob_id == 0)
457 goto fallback;
458
459 blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
460 if (!blob)
461 goto fallback;
462
463 fmt_mod_blob = blob->data;
464 blob_formats = formats_ptr(fmt_mod_blob);
465 blob_modifiers = modifiers_ptr(fmt_mod_blob);
466
Scott Anderson74663092021-02-01 15:46:33 -0300467 assert(kplane->count_formats == fmt_mod_blob->count_formats);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100468
469 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
Scott Anderson74663092021-02-01 15:46:33 -0300470 fmt = weston_drm_format_array_add_format(&plane->formats,
471 blob_formats[i]);
472 if (!fmt) {
473 ret = -1;
474 goto out;
475 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100476
477 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
478 struct drm_format_modifier *mod = &blob_modifiers[j];
479
480 if ((i < mod->offset) || (i > mod->offset + 63))
481 continue;
482 if (!(mod->formats & (1 << (i - mod->offset))))
483 continue;
484
Scott Anderson74663092021-02-01 15:46:33 -0300485 ret = weston_drm_format_add_modifier(fmt, mod->modifier);
486 if (ret < 0)
487 goto out;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100488 }
489
Leandro Ribeiro98101e82021-04-21 11:46:35 -0300490 if (fmt->modifiers.size == 0)
491 weston_drm_format_array_remove_latest_format(&plane->formats);
leng.fang32af9fc2024-06-13 11:22:15 +0800492
493 if (fmt->format == DRM_FORMAT_NV12 ||
494 fmt->format == DRM_FORMAT_NV21)
495 plane->is_video_plane = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100496 }
497
Scott Anderson74663092021-02-01 15:46:33 -0300498out:
Daniel Stone4c2fc702019-06-18 11:12:07 +0100499 drmModeFreePropertyBlob(blob);
Scott Anderson74663092021-02-01 15:46:33 -0300500 return ret;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100501
502fallback:
Daniel Stone4c2fc702019-06-18 11:12:07 +0100503 /* No IN_FORMATS blob available, so just use the old. */
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900504 for (i = 0; i < kplane->count_formats; i++) {
Scott Anderson74663092021-02-01 15:46:33 -0300505 fmt = weston_drm_format_array_add_format(&plane->formats,
506 kplane->formats[i]);
507 if (!fmt)
508 return -1;
Leandro Ribeiro567cc922021-04-21 11:44:53 -0300509 ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_INVALID);
Scott Anderson74663092021-02-01 15:46:33 -0300510 if (ret < 0)
511 return -1;
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900512 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100513 return 0;
514}
515
516void
517drm_output_set_gamma(struct weston_output *output_base,
518 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
519{
520 int rc;
521 struct drm_output *output = to_drm_output(output_base);
522 struct drm_backend *backend =
523 to_drm_backend(output->base.compositor);
524
525 /* check */
526 if (output_base->gamma_size != size)
527 return;
528
529 rc = drmModeCrtcSetGamma(backend->drm.fd,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300530 output->crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100531 size, r, g, b);
532 if (rc)
533 weston_log("set gamma failed: %s\n", strerror(errno));
534}
535
536/**
537 * Mark an output state as current on the output, i.e. it has been
538 * submitted to the kernel. The mode argument determines whether this
539 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
540 * or asynchronously (in which case we wait for events to complete).
541 */
542static void
543drm_output_assign_state(struct drm_output_state *state,
544 enum drm_state_apply_mode mode)
545{
546 struct drm_output *output = state->output;
547 struct drm_backend *b = to_drm_backend(output->base.compositor);
548 struct drm_plane_state *plane_state;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530549 struct drm_head *head;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100550
551 assert(!output->state_last);
552
553 if (mode == DRM_STATE_APPLY_ASYNC)
554 output->state_last = output->state_cur;
555 else
556 drm_output_state_free(output->state_cur);
557
558 wl_list_remove(&state->link);
559 wl_list_init(&state->link);
560 state->pending_state = NULL;
561
562 output->state_cur = state;
563
564 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300565 drm_debug(b, "\t[CRTC:%u] setting pending flip\n",
566 output->crtc->crtc_id);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100567 output->atomic_complete_pending = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100568 }
569
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530570 if (b->atomic_modeset &&
571 state->protection == WESTON_HDCP_DISABLE)
572 wl_list_for_each(head, &output->base.head_list, base.output_link)
573 weston_head_set_content_protection_status(&head->base,
574 WESTON_HDCP_DISABLE);
575
Daniel Stone4c2fc702019-06-18 11:12:07 +0100576 /* Replace state_cur on each affected plane with the new state, being
577 * careful to dispose of orphaned (but only orphaned) previous state.
578 * If the previous state is not orphaned (still has an output_state
579 * attached), it will be disposed of by freeing the output_state. */
580 wl_list_for_each(plane_state, &state->plane_list, link) {
581 struct drm_plane *plane = plane_state->plane;
582
583 if (plane->state_cur && !plane->state_cur->output_state)
584 drm_plane_state_free(plane->state_cur, true);
585 plane->state_cur = plane_state;
586
587 if (mode != DRM_STATE_APPLY_ASYNC) {
588 plane_state->complete = true;
589 continue;
590 }
591
592 if (b->atomic_modeset)
593 continue;
594
595 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
596 if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100597 output->page_flip_pending = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100598 }
599}
600
601static void
602drm_output_set_cursor(struct drm_output_state *output_state)
603{
604 struct drm_output *output = output_state->output;
605 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300606 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100607 struct drm_plane *plane = output->cursor_plane;
608 struct drm_plane_state *state;
Stefan Agner974390a2019-07-08 00:42:05 +0200609 uint32_t handle;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100610
611 if (!plane)
612 return;
613
614 state = drm_output_state_get_existing_plane(output_state, plane);
615 if (!state)
616 return;
617
618 if (!state->fb) {
619 pixman_region32_fini(&plane->base.damage);
620 pixman_region32_init(&plane->base.damage);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300621 drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100622 return;
623 }
624
625 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
626 assert(!plane->state_cur->output || plane->state_cur->output == output);
627
Stefan Agner974390a2019-07-08 00:42:05 +0200628 handle = output->gbm_cursor_handle[output->current_cursor];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100629 if (plane->state_cur->fb != state->fb) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300630 if (drmModeSetCursor(b->drm.fd, crtc->crtc_id, handle,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100631 b->cursor_width, b->cursor_height)) {
632 weston_log("failed to set cursor: %s\n",
633 strerror(errno));
634 goto err;
635 }
636 }
637
638 pixman_region32_fini(&plane->base.damage);
639 pixman_region32_init(&plane->base.damage);
640
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300641 if (drmModeMoveCursor(b->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100642 state->dest_x, state->dest_y)) {
643 weston_log("failed to move cursor: %s\n", strerror(errno));
644 goto err;
645 }
646
647 return;
648
649err:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100650 b->cursors_are_broken = true;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300651 drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100652}
653
654static int
655drm_output_apply_state_legacy(struct drm_output_state *state)
656{
657 struct drm_output *output = state->output;
658 struct drm_backend *backend = to_drm_backend(output->base.compositor);
659 struct drm_plane *scanout_plane = output->scanout_plane;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300660 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100661 struct drm_property_info *dpms_prop;
662 struct drm_plane_state *scanout_state;
663 struct drm_mode *mode;
664 struct drm_head *head;
665 const struct pixel_format_info *pinfo = NULL;
666 uint32_t connectors[MAX_CLONED_CONNECTORS];
667 int n_conn = 0;
668 struct timespec now;
669 int ret = 0;
670
671 wl_list_for_each(head, &output->base.head_list, base.output_link) {
672 assert(n_conn < MAX_CLONED_CONNECTORS);
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300673 connectors[n_conn++] = head->connector.connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100674 }
675
676 /* If disable_planes is set then assign_planes() wasn't
677 * called for this render, so we could still have a stale
678 * cursor plane set up.
679 */
680 if (output->base.disable_planes) {
Alexandros Frantzis10937fe2021-06-14 13:09:44 +0300681 drm_output_set_cursor_view(output, NULL);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100682 if (output->cursor_plane) {
683 output->cursor_plane->base.x = INT32_MIN;
684 output->cursor_plane->base.y = INT32_MIN;
685 }
686 }
687
688 if (state->dpms != WESTON_DPMS_ON) {
689 if (output->cursor_plane) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300690 ret = drmModeSetCursor(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100691 0, 0, 0);
692 if (ret)
693 weston_log("drmModeSetCursor failed disable: %s\n",
694 strerror(errno));
695 }
696
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300697 ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, 0, 0, 0,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100698 NULL, 0, NULL);
699 if (ret)
700 weston_log("drmModeSetCrtc failed disabling: %s\n",
701 strerror(errno));
702
703 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
704 weston_compositor_read_presentation_clock(output->base.compositor, &now);
705 drm_output_update_complete(output,
706 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
707 now.tv_sec, now.tv_nsec / 1000);
708
709 return 0;
710 }
711
712 scanout_state =
713 drm_output_state_get_existing_plane(state, scanout_plane);
714
715 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
716 * legacy PageFlip API doesn't allow us to do clipping either. */
717 assert(scanout_state->src_x == 0);
718 assert(scanout_state->src_y == 0);
719 assert(scanout_state->src_w ==
720 (unsigned) (output->base.current_mode->width << 16));
721 assert(scanout_state->src_h ==
722 (unsigned) (output->base.current_mode->height << 16));
723 assert(scanout_state->dest_x == 0);
724 assert(scanout_state->dest_y == 0);
725 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
726 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
727 /* The legacy SetCrtc API doesn't support fences */
728 assert(scanout_state->in_fence_fd == -1);
729
730 mode = to_drm_mode(output->base.current_mode);
731 if (backend->state_invalid ||
732 !scanout_plane->state_cur->fb ||
733 scanout_plane->state_cur->fb->strides[0] !=
734 scanout_state->fb->strides[0]) {
735
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300736 ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100737 scanout_state->fb->fb_id,
738 0, 0,
739 connectors, n_conn,
740 &mode->mode_info);
741 if (ret) {
742 weston_log("set mode failed: %s\n", strerror(errno));
743 goto err;
744 }
745 }
746
747 pinfo = scanout_state->fb->format;
748 drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300749 crtc->crtc_id, scanout_state->plane->plane_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100750 pinfo ? pinfo->drm_format_name : "UNKNOWN");
751
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300752 if (drmModePageFlip(backend->drm.fd, crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100753 scanout_state->fb->fb_id,
754 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
755 weston_log("queueing pageflip failed: %s\n", strerror(errno));
756 goto err;
757 }
758
759 assert(!output->page_flip_pending);
760
761 if (output->pageflip_timer)
762 wl_event_source_timer_update(output->pageflip_timer,
763 backend->pageflip_timeout);
764
765 drm_output_set_cursor(state);
766
767 if (state->dpms != output->state_cur->dpms) {
768 wl_list_for_each(head, &output->base.head_list, base.output_link) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300769 dpms_prop = &head->connector.props[WDRM_CONNECTOR_DPMS];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100770 if (dpms_prop->prop_id == 0)
771 continue;
772
773 ret = drmModeConnectorSetProperty(backend->drm.fd,
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300774 head->connector.connector_id,
775 dpms_prop->prop_id,
776 state->dpms);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100777 if (ret) {
778 weston_log("DRM: DPMS: failed property set for %s\n",
779 head->base.name);
780 }
781 }
782 }
783
784 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
785
786 return 0;
787
788err:
Alexandros Frantzis10937fe2021-06-14 13:09:44 +0300789 drm_output_set_cursor_view(output, NULL);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100790 drm_output_state_free(state);
791 return -1;
792}
793
Daniel Stone4c2fc702019-06-18 11:12:07 +0100794static int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300795crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100796 enum wdrm_crtc_property prop, uint64_t val)
797{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300798 struct drm_property_info *info = &crtc->props_crtc[prop];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100799 int ret;
800
801 if (info->prop_id == 0)
802 return -1;
803
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300804 ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100805 val);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300806 drm_debug(crtc->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
807 (unsigned long) crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100808 (unsigned long) info->prop_id, info->name,
809 (unsigned long long) val, (unsigned long long) val);
810 return (ret <= 0) ? -1 : 0;
811}
812
813static int
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300814connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100815 enum wdrm_connector_property prop, uint64_t val)
816{
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300817 struct drm_property_info *info = &connector->props[prop];
818 uint32_t connector_id = connector->connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100819 int ret;
820
821 if (info->prop_id == 0)
822 return -1;
823
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300824 ret = drmModeAtomicAddProperty(req, connector_id, info->prop_id, val);
825 drm_debug(connector->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
826 (unsigned long) connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100827 (unsigned long) info->prop_id, info->name,
828 (unsigned long long) val, (unsigned long long) val);
829 return (ret <= 0) ? -1 : 0;
830}
831
832static int
833plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
834 enum wdrm_plane_property prop, uint64_t val)
835{
836 struct drm_property_info *info = &plane->props[prop];
837 int ret;
838
839 if (info->prop_id == 0)
840 return -1;
841
842 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
843 val);
844 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
845 (unsigned long) plane->plane_id,
846 (unsigned long) info->prop_id, info->name,
847 (unsigned long long) val, (unsigned long long) val);
848 return (ret <= 0) ? -1 : 0;
849}
850
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530851static bool
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300852drm_connector_has_prop(struct drm_connector *connector,
853 enum wdrm_connector_property prop)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530854{
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300855 if (connector->props[prop].prop_id != 0)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530856 return true;
857
858 return false;
859}
860
861/*
862 * This function converts the protection requests from weston_hdcp_protection
863 * corresponding drm values. These values can be set in "Content Protection"
864 * & "HDCP Content Type" connector properties.
865 */
866static void
867get_drm_protection_from_weston(enum weston_hdcp_protection weston_protection,
868 enum wdrm_content_protection_state *drm_protection,
869 enum wdrm_hdcp_content_type *drm_cp_type)
870{
871
872 switch (weston_protection) {
873 case WESTON_HDCP_DISABLE:
874 *drm_protection = WDRM_CONTENT_PROTECTION_UNDESIRED;
875 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
876 break;
877 case WESTON_HDCP_ENABLE_TYPE_0:
878 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
879 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
880 break;
881 case WESTON_HDCP_ENABLE_TYPE_1:
882 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
883 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE1;
884 break;
885 default:
886 assert(0 && "bad weston_hdcp_protection");
887 }
888}
889
890static void
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300891drm_connector_set_hdcp_property(struct drm_connector *connector,
892 enum weston_hdcp_protection protection,
893 drmModeAtomicReq *req)
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530894{
895 int ret;
896 enum wdrm_content_protection_state drm_protection;
897 enum wdrm_hdcp_content_type drm_cp_type;
898 struct drm_property_enum_info *enum_info;
899 uint64_t prop_val;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300900 struct drm_property_info *props = connector->props;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530901
902 get_drm_protection_from_weston(protection, &drm_protection,
903 &drm_cp_type);
904
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300905 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_CONTENT_PROTECTION))
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530906 return;
907
908 /*
909 * Content-type property is not exposed for platforms not supporting
910 * HDCP2.2, therefore, type-1 cannot be supported. The type-0 content
911 * still can be supported if the content-protection property is exposed.
912 */
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300913 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE) &&
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530914 drm_cp_type != WDRM_HDCP_CONTENT_TYPE0)
915 return;
916
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300917 enum_info = props[WDRM_CONNECTOR_CONTENT_PROTECTION].enum_values;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530918 prop_val = enum_info[drm_protection].value;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300919 ret = connector_add_prop(req, connector,
920 WDRM_CONNECTOR_CONTENT_PROTECTION, prop_val);
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530921 assert(ret == 0);
922
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300923 if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE))
Ankit Nautiyalfc2c1802019-08-30 19:40:46 +0530924 return;
925
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300926 enum_info = props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE].enum_values;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530927 prop_val = enum_info[drm_cp_type].value;
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300928 ret = connector_add_prop(req, connector,
929 WDRM_CONNECTOR_HDCP_CONTENT_TYPE, prop_val);
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530930 assert(ret == 0);
931}
932
Daniel Stone4c2fc702019-06-18 11:12:07 +0100933static int
934drm_output_apply_state_atomic(struct drm_output_state *state,
935 drmModeAtomicReq *req,
936 uint32_t *flags)
937{
938 struct drm_output *output = state->output;
939 struct drm_backend *b = to_drm_backend(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300940 struct drm_crtc *crtc = output->crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100941 struct drm_plane_state *plane_state;
942 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
943 struct drm_head *head;
944 int ret = 0;
945
946 drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
947 (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
948 (unsigned long) output->base.id, output->base.name);
949
950 if (state->dpms != output->state_cur->dpms) {
951 drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
952 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
953 }
954
955 if (state->dpms == WESTON_DPMS_ON) {
956 ret = drm_mode_ensure_blob(b, current_mode);
957 if (ret != 0)
958 return ret;
959
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300960 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID,
Daniel Stone4c2fc702019-06-18 11:12:07 +0100961 current_mode->blob_id);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300962 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 1);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100963
964 /* No need for the DPMS property, since it is implicit in
965 * routing and CRTC activity. */
966 wl_list_for_each(head, &output->base.head_list, base.output_link) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300967 ret |= connector_add_prop(req, &head->connector,
968 WDRM_CONNECTOR_CRTC_ID,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300969 crtc->crtc_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100970 }
971 } else {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300972 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
973 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100974
975 /* No need for the DPMS property, since it is implicit in
976 * routing and CRTC activity. */
977 wl_list_for_each(head, &output->base.head_list, base.output_link)
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300978 ret |= connector_add_prop(req, &head->connector,
979 WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +0100980 }
981
Daniel Stone4c2fc702019-06-18 11:12:07 +0100982 if (ret != 0) {
983 weston_log("couldn't set atomic CRTC/connector state\n");
984 return ret;
985 }
chen.wang1fdc0f562024-09-04 07:57:16 +0000986 if ( !(*flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
987 drm_update_default_video_zorder(state);
988 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100989 wl_list_for_each(plane_state, &state->plane_list, link) {
990 struct drm_plane *plane = plane_state->plane;
991 const struct pixel_format_info *pinfo = NULL;
leng.fangc0af1fa2024-08-13 17:54:42 +0800992 int dest_x, dest_y;
993 uint32_t dest_w, dest_h;
leng.fang32af9fc2024-06-13 11:22:15 +0800994 if ( !plane_state->fb )
995 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100996
997 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
998 plane_state->fb ? plane_state->fb->fb_id : 0);
leng.fang32af9fc2024-06-13 11:22:15 +0800999
1000 drm_update_video_plane_info(plane_state, flags);
leng.fangc0af1fa2024-08-13 17:54:42 +08001001 drm_update_plane_info(plane_state, *flags, &dest_x, &dest_y, &dest_w, &dest_h);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001002 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001003 plane_state->fb ? crtc->crtc_id : 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001004 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
1005 plane_state->src_x);
1006 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
1007 plane_state->src_y);
1008 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
1009 plane_state->src_w);
1010 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
1011 plane_state->src_h);
1012 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
leng.fangc0af1fa2024-08-13 17:54:42 +08001013 dest_x);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001014 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
leng.fangc0af1fa2024-08-13 17:54:42 +08001015 dest_y);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001016 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
leng.fangc0af1fa2024-08-13 17:54:42 +08001017 dest_w);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001018 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
leng.fangc0af1fa2024-08-13 17:54:42 +08001019 dest_h);
leng.fanga0f20922024-10-11 17:23:59 +08001020 if (plane->props[WDRM_PLANE_ALPHA].prop_id != 0)
1021 ret |= plane_add_prop(req, plane, WDRM_PLANE_ALPHA,
1022 drm_get_alpha(plane_state));
Scott Anderson15c603c2020-06-02 17:39:43 +12001023 if (plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS].prop_id != 0)
1024 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS,
1025 plane_state->damage_blob_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001026
chen.wang1f06854b2024-09-26 11:26:04 +00001027 if (plane->is_video_plane ) {
1028 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] video plane, video_transform:%d\n",
1029 (unsigned long) plane->plane_id,
1030 plane_state->video_transform);
1031
1032 ret |= plane_add_prop(req, plane, WDRM_PLANE_VIDEO_ROTATION,
1033 1 << plane_state->video_transform);
1034 }
1035
Daniel Stone4c2fc702019-06-18 11:12:07 +01001036 if (plane_state->fb && plane_state->fb->format)
1037 pinfo = plane_state->fb->format;
1038
1039 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
1040 (unsigned long) plane->plane_id,
1041 pinfo ? pinfo->drm_format_name : "UNKNOWN");
1042
1043 if (plane_state->in_fence_fd >= 0) {
1044 ret |= plane_add_prop(req, plane,
1045 WDRM_PLANE_IN_FENCE_FD,
1046 plane_state->in_fence_fd);
1047 }
leng.fang32af9fc2024-06-13 11:22:15 +08001048#ifdef USE_DEFAULT_Z_ORDER
1049 //use drm default palne z-order
limin.tian85cd2462024-08-12 08:04:12 +00001050 if (!plane_state->plane->is_video_plane) {
1051 plane_state->zpos = DEFAULT_OSD_PLANE_ZPOS + plane_state->plane->plane_idx;
1052 ret |= plane_add_prop(req, plane,
1053 WDRM_PLANE_ZPOS,
1054 plane_state->zpos);
1055 }
chen.wang1fdc0f562024-09-04 07:57:16 +00001056 //video palne z-order
1057 if (plane_state->plane->is_video_plane) {
1058 ret |= plane_add_prop(req, plane,
1059 WDRM_PLANE_ZPOS,
1060 plane_state->video_zpos);
1061 }
leng.fang32af9fc2024-06-13 11:22:15 +08001062#else
Marius Vladcdd6fa22019-08-29 20:42:00 +03001063 /* do note, that 'invented' zpos values are set as immutable */
1064 if (plane_state->zpos != DRM_PLANE_ZPOS_INVALID_PLANE &&
1065 plane_state->plane->zpos_min != plane_state->plane->zpos_max)
1066 ret |= plane_add_prop(req, plane,
1067 WDRM_PLANE_ZPOS,
1068 plane_state->zpos);
leng.fang32af9fc2024-06-13 11:22:15 +08001069#endif
Marius Vladcdd6fa22019-08-29 20:42:00 +03001070
Daniel Stone4c2fc702019-06-18 11:12:07 +01001071 if (ret != 0) {
1072 weston_log("couldn't set plane state\n");
1073 return ret;
1074 }
1075 }
1076
1077 return 0;
1078}
1079
1080/**
1081 * Helper function used only by drm_pending_state_apply, with the same
1082 * guarantees and constraints as that function.
1083 */
1084static int
1085drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
1086 enum drm_state_apply_mode mode)
1087{
1088 struct drm_backend *b = pending_state->backend;
1089 struct drm_output_state *output_state, *tmp;
1090 struct drm_plane *plane;
1091 drmModeAtomicReq *req = drmModeAtomicAlloc();
1092 uint32_t flags;
1093 int ret = 0;
leng.fang13fd3982024-07-03 19:09:58 +08001094 bool mode_changed = false;
1095 bool state_invalid = false;
1096 bool allow_modeset = false;
leng.fang69a93e32024-08-08 16:31:01 +08001097 int possible = 0;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001098
1099 if (!req)
1100 return -1;
1101
1102 switch (mode) {
1103 case DRM_STATE_APPLY_SYNC:
1104 flags = 0;
1105 break;
1106 case DRM_STATE_APPLY_ASYNC:
1107 flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
1108 break;
1109 case DRM_STATE_TEST_ONLY:
1110 flags = DRM_MODE_ATOMIC_TEST_ONLY;
1111 break;
1112 }
1113
leng.fang13fd3982024-07-03 19:09:58 +08001114 state_invalid = b->state_invalid;
1115 allow_modeset = b->allow_modeset;
leng.fang3e8a4b52024-07-24 14:51:30 +08001116#ifdef ENABLE_MODE_POLICY
leng.fang69a93e32024-08-08 16:31:01 +08001117 mode_policy_update_modeset(&b->state_invalid, &b->allow_modeset, &possible);
leng.fang3e8a4b52024-07-24 14:51:30 +08001118#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001119 if (b->state_invalid) {
1120 struct weston_head *head_base;
1121 struct drm_head *head;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001122 struct drm_crtc *crtc;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001123 uint32_t connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001124 int err;
1125
1126 drm_debug(b, "\t\t[atomic] previous state invalid; "
1127 "starting with fresh state\n");
1128
1129 /* If we need to reset all our state (e.g. because we've
1130 * just started, or just been VT-switched in), explicitly
1131 * disable all the CRTCs and connectors we aren't using. */
leng.fang32af9fc2024-06-13 11:22:15 +08001132#if 0
1133
Daniel Stone4c2fc702019-06-18 11:12:07 +01001134 wl_list_for_each(head_base,
1135 &b->compositor->head_list, compositor_link) {
1136 struct drm_property_info *info;
1137
1138 if (weston_head_is_enabled(head_base))
1139 continue;
1140
1141 head = to_drm_head(head_base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001142 connector_id = head->connector.connector_id;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001143
1144 drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
1145 head_base->name);
1146
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001147 info = &head->connector.props[WDRM_CONNECTOR_CRTC_ID];
1148 err = drmModeAtomicAddProperty(req, connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001149 info->prop_id, 0);
1150 drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001151 (unsigned long) connector_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001152 (unsigned long) info->prop_id,
1153 info->name);
1154 if (err <= 0)
1155 ret = -1;
1156 }
1157
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001158 wl_list_for_each(crtc, &b->crtc_list, link) {
Daniel Stone4c2fc702019-06-18 11:12:07 +01001159 struct drm_property_info *info;
1160 drmModeObjectProperties *props;
1161 uint64_t active;
1162
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001163 /* Ignore CRTCs that are in use */
1164 if (crtc->output)
1165 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001166
1167 /* We can't emit a disable on a CRTC that's already
1168 * off, as the kernel will refuse to generate an event
1169 * for an off->off state and fail the commit.
1170 */
1171 props = drmModeObjectGetProperties(b->drm.fd,
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001172 crtc->crtc_id,
Daniel Stone4c2fc702019-06-18 11:12:07 +01001173 DRM_MODE_OBJECT_CRTC);
1174 if (!props) {
1175 ret = -1;
1176 continue;
1177 }
1178
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001179 info = &crtc->props_crtc[WDRM_CRTC_ACTIVE];
Daniel Stone4c2fc702019-06-18 11:12:07 +01001180 active = drm_property_get_value(info, props, 0);
1181 drmModeFreeObjectProperties(props);
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001182 if (active == 0)
Daniel Stone4c2fc702019-06-18 11:12:07 +01001183 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001184
1185 drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001186 (unsigned long) crtc->crtc_id);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001187
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001188 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
1189 ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001190 }
limin.tian4c74de22024-12-24 03:34:26 +00001191
Daniel Stone4c2fc702019-06-18 11:12:07 +01001192
1193 /* Disable all the planes; planes which are being used will
1194 * override this state in the output-state application. */
1195 wl_list_for_each(plane, &b->plane_list, link) {
1196 drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
1197 (unsigned long) plane->plane_id);
leng.fang69a93e32024-08-08 16:31:01 +08001198 if (possible && (possible & plane->possible_crtcs) == 0)
1199 continue;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001200 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
1201 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
1202 }
limin.tian4c74de22024-12-24 03:34:26 +00001203#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001204
leng.fang13fd3982024-07-03 19:09:58 +08001205 if (b->allow_modeset) {
leng.fang32af9fc2024-06-13 11:22:15 +08001206 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
leng.fang13fd3982024-07-03 19:09:58 +08001207 mode_changed = true;
limin.tianaaaff782024-12-20 09:49:25 +00001208 weston_log("\n allow_modeset:%d\n", b->allow_modeset);
leng.fang13fd3982024-07-03 19:09:58 +08001209 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001210 }
1211
1212 wl_list_for_each(output_state, &pending_state->output_list, link) {
1213 if (output_state->output->virtual)
1214 continue;
1215 if (mode == DRM_STATE_APPLY_SYNC)
1216 assert(output_state->dpms == WESTON_DPMS_OFF);
1217 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
1218 }
1219
1220 if (ret != 0) {
1221 weston_log("atomic: couldn't compile atomic state\n");
1222 goto out;
1223 }
leng.fang32af9fc2024-06-13 11:22:15 +08001224#ifdef ENABLE_DRM_HELP
1225 ret |= help_atomic_req_add_prop(req);
1226#endif
Daniel Stone4c2fc702019-06-18 11:12:07 +01001227
leng.fang91856072024-06-07 14:12:54 +08001228#ifdef ENABLE_MODE_POLICY
leng.fangb1081a32024-06-25 14:41:37 +08001229 if (mode != DRM_STATE_TEST_ONLY &&
leng.fang13fd3982024-07-03 19:09:58 +08001230 mode_policy_add_prop(req, mode_changed) > 0) {
leng.fangb1081a32024-06-25 14:41:37 +08001231 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
limin.tianaaaff782024-12-20 09:49:25 +00001232 weston_log("\n add prop, allow_modeset:%d\n", b->allow_modeset);
leng.fangb1081a32024-06-25 14:41:37 +08001233 }
leng.fang91856072024-06-07 14:12:54 +08001234#endif
1235
Daniel Stone4c2fc702019-06-18 11:12:07 +01001236 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
1237 drm_debug(b, "[atomic] drmModeAtomicCommit\n");
1238
leng.fang32af9fc2024-06-13 11:22:15 +08001239 drm_update_buffer_commit_result(ret, pending_state);
1240
Daniel Stone4c2fc702019-06-18 11:12:07 +01001241 /* Test commits do not take ownership of the state; return
1242 * without freeing here. */
1243 if (mode == DRM_STATE_TEST_ONLY) {
1244 drmModeAtomicFree(req);
1245 return ret;
1246 }
1247
1248 if (ret != 0) {
leng.fang13fd3982024-07-03 19:09:58 +08001249 weston_log("atomic: couldn't commit new state: %s, flags: %x\n",
1250 strerror(errno), flags);
leng.fangbb91d4d2024-10-16 10:50:11 +08001251 drm_commit_fail_pending_state_free(pending_state);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001252 goto out;
1253 }
1254
1255 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1256 link)
1257 drm_output_assign_state(output_state, mode);
1258
limin.tianaaaff782024-12-20 09:49:25 +00001259 if (/*mode_changed &&*/
leng.fang13fd3982024-07-03 19:09:58 +08001260 state_invalid == b->state_invalid &&
1261 allow_modeset == b->allow_modeset) {
1262 b->state_invalid = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001263
leng.fang13fd3982024-07-03 19:09:58 +08001264 if (b->allow_modeset)
1265 b->allow_modeset = false;
1266 }
leng.fang69a93e32024-08-08 16:31:01 +08001267
1268 if (b->state_invalid && !allow_modeset &&
1269 state_invalid == b->state_invalid)
1270 b->state_invalid = false;
1271
Daniel Stone4c2fc702019-06-18 11:12:07 +01001272 assert(wl_list_empty(&pending_state->output_list));
1273
1274out:
1275 drmModeAtomicFree(req);
1276 drm_pending_state_free(pending_state);
1277 return ret;
1278}
Daniel Stone4c2fc702019-06-18 11:12:07 +01001279
1280/**
1281 * Tests a pending state, to see if the kernel will accept the update as
1282 * constructed.
1283 *
1284 * Using atomic modesetting, the kernel performs the same checks as it would
1285 * on a real commit, returning success or failure without actually modifying
1286 * the running state. It does not return -EBUSY if there are pending updates
1287 * in flight, so states may be tested at any point, however this means a
1288 * state which passed testing may fail on a real commit if the timing is not
1289 * respected (e.g. committing before the previous commit has completed).
1290 *
1291 * Without atomic modesetting, we have no way to check, so we optimistically
1292 * claim it will work.
1293 *
1294 * Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
1295 * function does _not_ take ownership of pending_state, nor does it clear
1296 * state_invalid.
1297 */
1298int
1299drm_pending_state_test(struct drm_pending_state *pending_state)
1300{
Daniel Stone4c2fc702019-06-18 11:12:07 +01001301 struct drm_backend *b = pending_state->backend;
1302
1303 if (b->atomic_modeset)
1304 return drm_pending_state_apply_atomic(pending_state,
1305 DRM_STATE_TEST_ONLY);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001306
1307 /* We have no way to test state before application on the legacy
1308 * modesetting API, so just claim it succeeded. */
1309 return 0;
1310}
1311
1312/**
1313 * Applies all of a pending_state asynchronously: the primary entry point for
1314 * applying KMS state to a device. Updates the state for all outputs in the
1315 * pending_state, as well as disabling any unclaimed outputs.
1316 *
1317 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1318 */
1319int
1320drm_pending_state_apply(struct drm_pending_state *pending_state)
1321{
1322 struct drm_backend *b = pending_state->backend;
1323 struct drm_output_state *output_state, *tmp;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001324 struct drm_crtc *crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001325
Daniel Stone4c2fc702019-06-18 11:12:07 +01001326 if (b->atomic_modeset)
1327 return drm_pending_state_apply_atomic(pending_state,
1328 DRM_STATE_APPLY_ASYNC);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001329
1330 if (b->state_invalid) {
1331 /* If we need to reset all our state (e.g. because we've
1332 * just started, or just been VT-switched in), explicitly
1333 * disable all the CRTCs we aren't using. This also disables
1334 * all connectors on these CRTCs, so we don't need to do that
1335 * separately with the pre-atomic API. */
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001336 wl_list_for_each(crtc, &b->crtc_list, link) {
1337 if (crtc->output)
1338 continue;
1339 drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
1340 NULL, 0, NULL);
1341 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001342 }
1343
1344 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1345 link) {
1346 struct drm_output *output = output_state->output;
1347 int ret;
1348
1349 if (output->virtual) {
1350 drm_output_assign_state(output_state,
1351 DRM_STATE_APPLY_ASYNC);
1352 continue;
1353 }
1354
1355 ret = drm_output_apply_state_legacy(output_state);
1356 if (ret != 0) {
1357 weston_log("Couldn't apply state for output %s\n",
1358 output->base.name);
nerdopolisd2a320d2021-08-23 21:29:42 -04001359 weston_output_repaint_failed(&output->base);
1360 drm_output_state_free(output->state_cur);
1361 output->state_cur = drm_output_state_alloc(output, NULL);
1362 b->state_invalid = true;
1363 if (!b->use_pixman) {
1364 drm_output_fini_egl(output);
1365 drm_output_init_egl(output, b);
1366 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001367 }
1368 }
1369
1370 b->state_invalid = false;
1371
1372 assert(wl_list_empty(&pending_state->output_list));
1373
1374 drm_pending_state_free(pending_state);
1375
1376 return 0;
1377}
1378
1379/**
1380 * The synchronous version of drm_pending_state_apply. May only be used to
1381 * disable outputs. Does so synchronously: the request is guaranteed to have
1382 * completed on return, and the output will not be touched afterwards.
1383 *
1384 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1385 */
1386int
1387drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
1388{
1389 struct drm_backend *b = pending_state->backend;
1390 struct drm_output_state *output_state, *tmp;
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001391 struct drm_crtc *crtc;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001392
Daniel Stone4c2fc702019-06-18 11:12:07 +01001393 if (b->atomic_modeset)
1394 return drm_pending_state_apply_atomic(pending_state,
1395 DRM_STATE_APPLY_SYNC);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001396
1397 if (b->state_invalid) {
1398 /* If we need to reset all our state (e.g. because we've
1399 * just started, or just been VT-switched in), explicitly
1400 * disable all the CRTCs we aren't using. This also disables
1401 * all connectors on these CRTCs, so we don't need to do that
1402 * separately with the pre-atomic API. */
Leandro Ribeiro744c0cb2020-08-13 16:15:58 -03001403 wl_list_for_each(crtc, &b->crtc_list, link) {
1404 if (crtc->output)
1405 continue;
1406 drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
1407 NULL, 0, NULL);
1408 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001409 }
1410
1411 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1412 link) {
1413 int ret;
1414
1415 assert(output_state->dpms == WESTON_DPMS_OFF);
1416 ret = drm_output_apply_state_legacy(output_state);
1417 if (ret != 0) {
1418 weston_log("Couldn't apply state for output %s\n",
1419 output_state->output->base.name);
1420 }
1421 }
1422
1423 b->state_invalid = false;
1424
1425 assert(wl_list_empty(&pending_state->output_list));
1426
1427 drm_pending_state_free(pending_state);
1428
1429 return 0;
1430}
1431
1432void
1433drm_output_update_msc(struct drm_output *output, unsigned int seq)
1434{
1435 uint64_t msc_hi = output->base.msc >> 32;
1436
1437 if (seq < (output->base.msc & 0xffffffff))
1438 msc_hi++;
1439
1440 output->base.msc = (msc_hi << 32) + seq;
1441}
1442
1443static void
1444page_flip_handler(int fd, unsigned int frame,
1445 unsigned int sec, unsigned int usec, void *data)
1446{
1447 struct drm_output *output = data;
1448 struct drm_backend *b = to_drm_backend(output->base.compositor);
1449 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1450 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1451 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1452
1453 drm_output_update_msc(output, frame);
1454
1455 assert(!b->atomic_modeset);
1456 assert(output->page_flip_pending);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001457 output->page_flip_pending = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001458
1459 drm_output_update_complete(output, flags, sec, usec);
1460}
1461
Daniel Stone4c2fc702019-06-18 11:12:07 +01001462static void
1463atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
1464 unsigned int usec, unsigned int crtc_id, void *data)
1465{
1466 struct drm_backend *b = data;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001467 struct drm_crtc *crtc;
1468 struct drm_output *output;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001469 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1470 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1471 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1472
limin.tianc616dad2024-07-15 11:35:38 +00001473 struct timespec ts1, ts2, ts3;
1474 weston_compositor_get_time(&ts1);
1475
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001476 crtc = drm_crtc_find(b, crtc_id);
1477 assert(crtc);
1478
1479 output = crtc->output;
1480
leng.fang32af9fc2024-06-13 11:22:15 +08001481 if (crtc->output_change) {
1482 output = crtc->disable_output;
1483 }
1484
Daniel Stone4c2fc702019-06-18 11:12:07 +01001485 /* During the initial modeset, we can disable CRTCs which we don't
1486 * actually handle during normal operation; this will give us events
1487 * for unknown outputs. Ignore them. */
leng.fang32af9fc2024-06-13 11:22:15 +08001488 if ( (!output || !output->base.enabled) && !crtc->output_change)
Daniel Stone4c2fc702019-06-18 11:12:07 +01001489 return;
1490
1491 drm_output_update_msc(output, frame);
limin.tianc616dad2024-07-15 11:35:38 +00001492 weston_compositor_get_time(&ts2);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001493
leng.fang32af9fc2024-06-13 11:22:15 +08001494 drm_debug(b, "[atomic][CRTC:%u] flip processing started output_change:%d\n",
1495 crtc_id,crtc->output_change );
1496 if ( b->atomic_modeset && output->atomic_complete_pending) {
1497 //assert(b->atomic_modeset);
1498 //assert(output->atomic_complete_pending);
1499 output->atomic_complete_pending = false;
1500 drm_output_update_complete(output, flags, sec, usec);
1501 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001502
leng.fang32af9fc2024-06-13 11:22:15 +08001503 crtc->output_change = false;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001504 drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
limin.tianc616dad2024-07-15 11:35:38 +00001505
1506 weston_compositor_get_time(&ts3);
1507 if ( (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)) > 10000 )
1508 weston_log("\n %s %d take:(%lld %lld %lld)\n",
1509 __FUNCTION__,__LINE__,
1510 (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)),
1511 (timespec_to_usec(&ts2) - timespec_to_usec(&ts1)),
1512 (timespec_to_usec(&ts3) - timespec_to_usec(&ts2))
1513 );
leng.fang32af9fc2024-06-13 11:22:15 +08001514 atomic_flip_handler_time(b);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001515}
Daniel Stone4c2fc702019-06-18 11:12:07 +01001516
1517int
1518on_drm_input(int fd, uint32_t mask, void *data)
1519{
Daniel Stone4c2fc702019-06-18 11:12:07 +01001520 struct drm_backend *b = data;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001521 drmEventContext evctx;
limin.tianc616dad2024-07-15 11:35:38 +00001522 struct timespec ts1, ts2, ts3;
1523 weston_compositor_get_time(&ts1);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001524
1525 memset(&evctx, 0, sizeof evctx);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001526 evctx.version = 3;
1527 if (b->atomic_modeset)
1528 evctx.page_flip_handler2 = atomic_flip_handler;
1529 else
Daniel Stone4c2fc702019-06-18 11:12:07 +01001530 evctx.page_flip_handler = page_flip_handler;
limin.tianc616dad2024-07-15 11:35:38 +00001531
1532 weston_compositor_get_time(&ts2);
Daniel Stone4c2fc702019-06-18 11:12:07 +01001533 drmHandleEvent(fd, &evctx);
limin.tianc616dad2024-07-15 11:35:38 +00001534 weston_compositor_get_time(&ts3);
1535 if ( (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)) > 10000 )
1536 weston_log("\n %s %d %lld %lld,take:(%lld %lld %lld)\n",
1537 __FUNCTION__,__LINE__, timespec_to_usec(&ts1), timespec_to_usec(&ts3),
1538 (timespec_to_usec(&ts3) - timespec_to_usec(&ts1)),
1539 (timespec_to_usec(&ts2) - timespec_to_usec(&ts1)),
1540 (timespec_to_usec(&ts3) - timespec_to_usec(&ts2))
1541 );
Daniel Stone4c2fc702019-06-18 11:12:07 +01001542
1543 return 1;
1544}
1545
1546int
1547init_kms_caps(struct drm_backend *b)
1548{
1549 uint64_t cap;
1550 int ret;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001551
1552 weston_log("using %s\n", b->drm.filename);
1553
1554 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Pekka Paalanenf48277b2021-05-10 11:44:57 +03001555 if (ret != 0 || cap != 1) {
1556 weston_log("Error: kernel DRM KMS does not support DRM_CAP_TIMESTAMP_MONOTONIC.\n");
1557 return -1;
1558 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001559
Pekka Paalanenf48277b2021-05-10 11:44:57 +03001560 if (weston_compositor_set_presentation_clock(b->compositor, CLOCK_MONOTONIC) < 0) {
1561 weston_log("Error: failed to set presentation clock to CLOCK_MONOTONIC.\n");
Daniel Stone4c2fc702019-06-18 11:12:07 +01001562 return -1;
1563 }
1564
1565 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
1566 if (ret == 0)
1567 b->cursor_width = cap;
1568 else
1569 b->cursor_width = 64;
1570
1571 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1572 if (ret == 0)
1573 b->cursor_height = cap;
1574 else
1575 b->cursor_height = 64;
1576
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001577 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1578 if (ret) {
1579 weston_log("Error: drm card doesn't support universal planes!\n");
1580 return -1;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001581 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001582
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001583 if (!getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone4c2fc702019-06-18 11:12:07 +01001584 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
1585 if (ret != 0)
1586 cap = 0;
1587 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
1588 b->atomic_modeset = ((ret == 0) && (cap == 1));
1589 }
Daniel Stone4c2fc702019-06-18 11:12:07 +01001590 weston_log("DRM: %s atomic modesetting\n",
1591 b->atomic_modeset ? "supports" : "does not support");
1592
Stefan Agner465ab2c2020-06-17 23:36:44 +02001593 if (!getenv("WESTON_DISABLE_GBM_MODIFIERS")) {
1594 ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
1595 if (ret == 0)
1596 b->fb_modifiers = cap;
1597 }
1598 weston_log("DRM: %s GBM modifiers\n",
1599 b->fb_modifiers ? "supports" : "does not support");
Daniel Stone4c2fc702019-06-18 11:12:07 +01001600
Leandro Ribeiro96bef052020-09-09 15:23:49 -03001601 drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
1602
Daniel Stone4c2fc702019-06-18 11:12:07 +01001603 /*
1604 * KMS support for hardware planes cannot properly synchronize
1605 * without nuclear page flip. Without nuclear/atomic, hw plane
1606 * and cursor plane updates would either tear or cause extra
1607 * waits for vblanks which means dropping the compositor framerate
1608 * to a fraction. For cursors, it's not so bad, so they are
1609 * enabled.
1610 */
1611 if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001612 b->sprites_are_broken = true;
Daniel Stone4c2fc702019-06-18 11:12:07 +01001613
1614 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
1615 b->aspect_ratio_supported = (ret == 0);
1616 weston_log("DRM: %s picture aspect ratio\n",
1617 b->aspect_ratio_supported ? "supports" : "does not support");
1618
1619 return 0;
1620}