blob: 4cb242d3adfe7481223dbf7c4dc64d594629eed3 [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>
36#include <drm_fourcc.h>
37
Daniel Stone4c2fc702019-06-18 11:12:07 +010038#include <libweston/libweston.h>
39#include <libweston/backend-drm.h>
40#include "shared/helpers.h"
41#include "drm-internal.h"
42#include "pixel-formats.h"
43#include "presentation-time-server-protocol.h"
44
Tomohito Esaki29beeaf2019-06-24 17:23:44 +090045#ifndef DRM_FORMAT_MOD_LINEAR
46#define DRM_FORMAT_MOD_LINEAR 0
47#endif
48
Daniel Stone4c2fc702019-06-18 11:12:07 +010049struct drm_property_enum_info plane_type_enums[] = {
50 [WDRM_PLANE_TYPE_PRIMARY] = {
51 .name = "Primary",
52 },
53 [WDRM_PLANE_TYPE_OVERLAY] = {
54 .name = "Overlay",
55 },
56 [WDRM_PLANE_TYPE_CURSOR] = {
57 .name = "Cursor",
58 },
59};
60
61const struct drm_property_info plane_props[] = {
62 [WDRM_PLANE_TYPE] = {
63 .name = "type",
64 .enum_values = plane_type_enums,
65 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
66 },
67 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
68 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
69 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
70 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
71 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
72 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
73 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
74 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
75 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
76 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
77 [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" },
78 [WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
79 [WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
80};
81
82struct drm_property_enum_info dpms_state_enums[] = {
83 [WDRM_DPMS_STATE_OFF] = {
84 .name = "Off",
85 },
86 [WDRM_DPMS_STATE_ON] = {
87 .name = "On",
88 },
89 [WDRM_DPMS_STATE_STANDBY] = {
90 .name = "Standby",
91 },
92 [WDRM_DPMS_STATE_SUSPEND] = {
93 .name = "Suspend",
94 },
95};
96
Ankit Nautiyala344fe32019-05-14 18:36:08 +053097struct drm_property_enum_info content_protection_enums[] = {
98 [WDRM_CONTENT_PROTECTION_UNDESIRED] = {
99 .name = "Undesired",
100 },
101 [WDRM_CONTENT_PROTECTION_DESIRED] = {
102 .name = "Desired",
103 },
104 [WDRM_CONTENT_PROTECTION_ENABLED] = {
105 .name = "Enabled",
106 },
107};
108
109struct drm_property_enum_info hdcp_content_type_enums[] = {
110 [WDRM_HDCP_CONTENT_TYPE0] = {
111 .name = "HDCP Type0",
112 },
113 [WDRM_HDCP_CONTENT_TYPE1] = {
114 .name = "HDCP Type1",
115 },
116};
117
Daniel Stone4c2fc702019-06-18 11:12:07 +0100118const struct drm_property_info connector_props[] = {
119 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
120 [WDRM_CONNECTOR_DPMS] = {
121 .name = "DPMS",
122 .enum_values = dpms_state_enums,
123 .num_enum_values = WDRM_DPMS_STATE__COUNT,
124 },
125 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
126 [WDRM_CONNECTOR_NON_DESKTOP] = { .name = "non-desktop", },
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530127 [WDRM_CONNECTOR_CONTENT_PROTECTION] = {
128 .name = "Content Protection",
129 .enum_values = content_protection_enums,
130 .num_enum_values = WDRM_CONTENT_PROTECTION__COUNT,
131 },
132 [WDRM_CONNECTOR_HDCP_CONTENT_TYPE] = {
133 .name = "HDCP Content Type",
134 .enum_values = hdcp_content_type_enums,
135 .num_enum_values = WDRM_HDCP_CONTENT_TYPE__COUNT,
136 },
Daniel Stone4c2fc702019-06-18 11:12:07 +0100137};
138
139const struct drm_property_info crtc_props[] = {
140 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
141 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
142};
143
144
145/**
146 * Mode for drm_pending_state_apply and co.
147 */
148enum drm_state_apply_mode {
149 DRM_STATE_APPLY_SYNC, /**< state fully processed */
150 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
151 DRM_STATE_TEST_ONLY, /**< test if the state can be applied */
152};
153
154/**
155 * Get the current value of a KMS property
156 *
157 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
158 * for the target property, return the current value of that property,
159 * with an optional default. If the property is a KMS enum type, the return
160 * value will be translated into the appropriate internal enum.
161 *
162 * If the property is not present, the default value will be returned.
163 *
164 * @param info Internal structure for property to look up
165 * @param props Raw KMS properties for the target object
166 * @param def Value to return if property is not found
167 */
168uint64_t
169drm_property_get_value(struct drm_property_info *info,
170 const drmModeObjectProperties *props,
171 uint64_t def)
172{
173 unsigned int i;
174
175 if (info->prop_id == 0)
176 return def;
177
178 for (i = 0; i < props->count_props; i++) {
179 unsigned int j;
180
181 if (props->props[i] != info->prop_id)
182 continue;
183
184 /* Simple (non-enum) types can return the value directly */
185 if (info->num_enum_values == 0)
186 return props->prop_values[i];
187
188 /* Map from raw value to enum value */
189 for (j = 0; j < info->num_enum_values; j++) {
190 if (!info->enum_values[j].valid)
191 continue;
192 if (info->enum_values[j].value != props->prop_values[i])
193 continue;
194
195 return j;
196 }
197
198 /* We don't have a mapping for this enum; return default. */
199 break;
200 }
201
202 return def;
203}
204
205/**
Marius Vlad1accffe2019-11-01 12:00:09 +0200206 * Get the current range values of a KMS property
207 *
208 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
209 * for the target property, return the current range values of that property,
210 *
211 * If the property is not present, or there's no it is not a prop range then
212 * NULL will be returned.
213 *
214 * @param info Internal structure for property to look up
215 * @param props Raw KMS properties for the target object
216 */
217uint64_t *
218drm_property_get_range_values(struct drm_property_info *info,
219 const drmModeObjectProperties *props)
220{
221 unsigned int i;
222
223 if (info->prop_id == 0)
224 return NULL;
225
226 for (i = 0; i < props->count_props; i++) {
227
228 if (props->props[i] != info->prop_id)
229 continue;
230
231 if (!(info->flags & DRM_MODE_PROP_RANGE) &&
232 !(info->flags & DRM_MODE_PROP_SIGNED_RANGE))
233 continue;
234
235 return info->range_values;
236 }
237
238 return NULL;
239}
240
241/**
Daniel Stone4c2fc702019-06-18 11:12:07 +0100242 * Cache DRM property values
243 *
244 * Update a per-object array of drm_property_info structures, given the
245 * DRM properties of the object.
246 *
247 * Call this every time an object newly appears (note that only connectors
248 * can be hotplugged), the first time it is seen, or when its status changes
249 * in a way which invalidates the potential property values (currently, the
250 * only case for this is connector hotplug).
251 *
252 * This updates the property IDs and enum values within the drm_property_info
253 * array.
254 *
255 * DRM property enum values are dynamic at runtime; the user must query the
256 * property to find out the desired runtime value for a requested string
257 * name. Using the 'type' field on planes as an example, there is no single
258 * hardcoded constant for primary plane types; instead, the property must be
259 * queried at runtime to find the value associated with the string "Primary".
260 *
261 * This helper queries and caches the enum values, to allow us to use a set
262 * of compile-time-constant enums portably across various implementations.
263 * The values given in enum_names are searched for, and stored in the
264 * same-indexed field of the map array.
265 *
266 * @param b DRM backend object
267 * @param src DRM property info array to source from
268 * @param info DRM property info array to copy into
269 * @param num_infos Number of entries in the source array
270 * @param props DRM object properties for the object
271 */
272void
273drm_property_info_populate(struct drm_backend *b,
274 const struct drm_property_info *src,
275 struct drm_property_info *info,
276 unsigned int num_infos,
277 drmModeObjectProperties *props)
278{
279 drmModePropertyRes *prop;
280 unsigned i, j;
281
282 for (i = 0; i < num_infos; i++) {
283 unsigned int j;
284
285 info[i].name = src[i].name;
286 info[i].prop_id = 0;
287 info[i].num_enum_values = src[i].num_enum_values;
288
289 if (src[i].num_enum_values == 0)
290 continue;
291
292 info[i].enum_values =
293 malloc(src[i].num_enum_values *
294 sizeof(*info[i].enum_values));
295 assert(info[i].enum_values);
296 for (j = 0; j < info[i].num_enum_values; j++) {
297 info[i].enum_values[j].name = src[i].enum_values[j].name;
298 info[i].enum_values[j].valid = false;
299 }
300 }
301
302 for (i = 0; i < props->count_props; i++) {
303 unsigned int k;
304
305 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
306 if (!prop)
307 continue;
308
309 for (j = 0; j < num_infos; j++) {
310 if (!strcmp(prop->name, info[j].name))
311 break;
312 }
313
314 /* We don't know/care about this property. */
315 if (j == num_infos) {
316#ifdef DEBUG
317 weston_log("DRM debug: unrecognized property %u '%s'\n",
318 prop->prop_id, prop->name);
319#endif
320 drmModeFreeProperty(prop);
321 continue;
322 }
323
324 if (info[j].num_enum_values == 0 &&
325 (prop->flags & DRM_MODE_PROP_ENUM)) {
326 weston_log("DRM: expected property %s to not be an"
327 " enum, but it is; ignoring\n", prop->name);
328 drmModeFreeProperty(prop);
329 continue;
330 }
331
332 info[j].prop_id = props->props[i];
Marius Vlad1accffe2019-11-01 12:00:09 +0200333 info[j].flags = prop->flags;
334
335 if (prop->flags & DRM_MODE_PROP_RANGE ||
336 prop->flags & DRM_MODE_PROP_SIGNED_RANGE) {
337 info[j].num_range_values = prop->count_values;
338 for (int i = 0; i < prop->count_values; i++)
339 info[j].range_values[i] = prop->values[i];
340 }
341
Daniel Stone4c2fc702019-06-18 11:12:07 +0100342
343 if (info[j].num_enum_values == 0) {
344 drmModeFreeProperty(prop);
345 continue;
346 }
347
348 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
349 weston_log("DRM: expected property %s to be an enum,"
350 " but it is not; ignoring\n", prop->name);
351 drmModeFreeProperty(prop);
352 info[j].prop_id = 0;
353 continue;
354 }
355
356 for (k = 0; k < info[j].num_enum_values; k++) {
357 int l;
358
359 for (l = 0; l < prop->count_enums; l++) {
360 if (!strcmp(prop->enums[l].name,
361 info[j].enum_values[k].name))
362 break;
363 }
364
365 if (l == prop->count_enums)
366 continue;
367
368 info[j].enum_values[k].valid = true;
369 info[j].enum_values[k].value = prop->enums[l].value;
370 }
371
372 drmModeFreeProperty(prop);
373 }
374
375#ifdef DEBUG
376 for (i = 0; i < num_infos; i++) {
377 if (info[i].prop_id == 0)
378 weston_log("DRM warning: property '%s' missing\n",
379 info[i].name);
380 }
381#endif
382}
383
384/**
385 * Free DRM property information
386 *
387 * Frees all memory associated with a DRM property info array and zeroes
388 * it out, leaving it usable for a further drm_property_info_update() or
389 * drm_property_info_free().
390 *
391 * @param info DRM property info array
392 * @param num_props Number of entries in array to free
393 */
394void
395drm_property_info_free(struct drm_property_info *info, int num_props)
396{
397 int i;
398
399 for (i = 0; i < num_props; i++)
400 free(info[i].enum_values);
401
402 memset(info, 0, sizeof(*info) * num_props);
403}
404
405#ifdef HAVE_DRM_FORMATS_BLOB
406static inline uint32_t *
407formats_ptr(struct drm_format_modifier_blob *blob)
408{
409 return (uint32_t *)(((char *)blob) + blob->formats_offset);
410}
411
412static inline struct drm_format_modifier *
413modifiers_ptr(struct drm_format_modifier_blob *blob)
414{
415 return (struct drm_format_modifier *)
416 (((char *)blob) + blob->modifiers_offset);
417}
418#endif
419
420/**
421 * Populates the plane's formats array, using either the IN_FORMATS blob
422 * property (if available), or the plane's format list if not.
423 */
424int
425drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
426 const drmModeObjectProperties *props)
427{
428 unsigned i;
429#ifdef HAVE_DRM_FORMATS_BLOB
430 drmModePropertyBlobRes *blob;
431 struct drm_format_modifier_blob *fmt_mod_blob;
432 struct drm_format_modifier *blob_modifiers;
433 uint32_t *blob_formats;
434 uint32_t blob_id;
435
436 blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
437 props,
438 0);
439 if (blob_id == 0)
440 goto fallback;
441
442 blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
443 if (!blob)
444 goto fallback;
445
446 fmt_mod_blob = blob->data;
447 blob_formats = formats_ptr(fmt_mod_blob);
448 blob_modifiers = modifiers_ptr(fmt_mod_blob);
449
450 if (plane->count_formats != fmt_mod_blob->count_formats) {
451 weston_log("DRM backend: format count differs between "
452 "plane (%d) and IN_FORMATS (%d)\n",
453 plane->count_formats,
454 fmt_mod_blob->count_formats);
455 weston_log("This represents a kernel bug; Weston is "
456 "unable to continue.\n");
457 abort();
458 }
459
460 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
461 uint32_t count_modifiers = 0;
462 uint64_t *modifiers = NULL;
463 unsigned j;
464
465 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
466 struct drm_format_modifier *mod = &blob_modifiers[j];
467
468 if ((i < mod->offset) || (i > mod->offset + 63))
469 continue;
470 if (!(mod->formats & (1 << (i - mod->offset))))
471 continue;
472
473 modifiers = realloc(modifiers,
474 (count_modifiers + 1) *
475 sizeof(modifiers[0]));
476 assert(modifiers);
477 modifiers[count_modifiers++] = mod->modifier;
478 }
479
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900480 if (count_modifiers == 0) {
481 modifiers = malloc(sizeof(*modifiers));
482 *modifiers = DRM_FORMAT_MOD_LINEAR;
483 count_modifiers = 1;
484 }
485
Daniel Stone4c2fc702019-06-18 11:12:07 +0100486 plane->formats[i].format = blob_formats[i];
487 plane->formats[i].modifiers = modifiers;
488 plane->formats[i].count_modifiers = count_modifiers;
489 }
490
491 drmModeFreePropertyBlob(blob);
492
493 return 0;
494
495fallback:
496#endif
497 /* No IN_FORMATS blob available, so just use the old. */
498 assert(plane->count_formats == kplane->count_formats);
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900499 for (i = 0; i < kplane->count_formats; i++) {
Daniel Stone4c2fc702019-06-18 11:12:07 +0100500 plane->formats[i].format = kplane->formats[i];
Tomohito Esaki29beeaf2019-06-24 17:23:44 +0900501 plane->formats[i].modifiers = malloc(sizeof(uint64_t));
502 plane->formats[i].modifiers[0] = DRM_FORMAT_MOD_LINEAR;
503 plane->formats[i].count_modifiers = 1;
504 }
Daniel Stone4c2fc702019-06-18 11:12:07 +0100505
506 return 0;
507}
508
509void
510drm_output_set_gamma(struct weston_output *output_base,
511 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
512{
513 int rc;
514 struct drm_output *output = to_drm_output(output_base);
515 struct drm_backend *backend =
516 to_drm_backend(output->base.compositor);
517
518 /* check */
519 if (output_base->gamma_size != size)
520 return;
521
522 rc = drmModeCrtcSetGamma(backend->drm.fd,
523 output->crtc_id,
524 size, r, g, b);
525 if (rc)
526 weston_log("set gamma failed: %s\n", strerror(errno));
527}
528
529/**
530 * Mark an output state as current on the output, i.e. it has been
531 * submitted to the kernel. The mode argument determines whether this
532 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
533 * or asynchronously (in which case we wait for events to complete).
534 */
535static void
536drm_output_assign_state(struct drm_output_state *state,
537 enum drm_state_apply_mode mode)
538{
539 struct drm_output *output = state->output;
540 struct drm_backend *b = to_drm_backend(output->base.compositor);
541 struct drm_plane_state *plane_state;
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530542 struct drm_head *head;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100543
544 assert(!output->state_last);
545
546 if (mode == DRM_STATE_APPLY_ASYNC)
547 output->state_last = output->state_cur;
548 else
549 drm_output_state_free(output->state_cur);
550
551 wl_list_remove(&state->link);
552 wl_list_init(&state->link);
553 state->pending_state = NULL;
554
555 output->state_cur = state;
556
557 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
558 drm_debug(b, "\t[CRTC:%u] setting pending flip\n", output->crtc_id);
559 output->atomic_complete_pending = 1;
560 }
561
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530562 if (b->atomic_modeset &&
563 state->protection == WESTON_HDCP_DISABLE)
564 wl_list_for_each(head, &output->base.head_list, base.output_link)
565 weston_head_set_content_protection_status(&head->base,
566 WESTON_HDCP_DISABLE);
567
Daniel Stone4c2fc702019-06-18 11:12:07 +0100568 /* Replace state_cur on each affected plane with the new state, being
569 * careful to dispose of orphaned (but only orphaned) previous state.
570 * If the previous state is not orphaned (still has an output_state
571 * attached), it will be disposed of by freeing the output_state. */
572 wl_list_for_each(plane_state, &state->plane_list, link) {
573 struct drm_plane *plane = plane_state->plane;
574
575 if (plane->state_cur && !plane->state_cur->output_state)
576 drm_plane_state_free(plane->state_cur, true);
577 plane->state_cur = plane_state;
578
579 if (mode != DRM_STATE_APPLY_ASYNC) {
580 plane_state->complete = true;
581 continue;
582 }
583
584 if (b->atomic_modeset)
585 continue;
586
587 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
588 if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
589 output->page_flip_pending = 1;
590 }
591}
592
593static void
594drm_output_set_cursor(struct drm_output_state *output_state)
595{
596 struct drm_output *output = output_state->output;
597 struct drm_backend *b = to_drm_backend(output->base.compositor);
598 struct drm_plane *plane = output->cursor_plane;
599 struct drm_plane_state *state;
Stefan Agner974390a2019-07-08 00:42:05 +0200600 uint32_t handle;
Daniel Stone4c2fc702019-06-18 11:12:07 +0100601
602 if (!plane)
603 return;
604
605 state = drm_output_state_get_existing_plane(output_state, plane);
606 if (!state)
607 return;
608
609 if (!state->fb) {
610 pixman_region32_fini(&plane->base.damage);
611 pixman_region32_init(&plane->base.damage);
612 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
613 return;
614 }
615
616 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
617 assert(!plane->state_cur->output || plane->state_cur->output == output);
618
Stefan Agner974390a2019-07-08 00:42:05 +0200619 handle = output->gbm_cursor_handle[output->current_cursor];
Daniel Stone4c2fc702019-06-18 11:12:07 +0100620 if (plane->state_cur->fb != state->fb) {
Daniel Stone4c2fc702019-06-18 11:12:07 +0100621 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
622 b->cursor_width, b->cursor_height)) {
623 weston_log("failed to set cursor: %s\n",
624 strerror(errno));
625 goto err;
626 }
627 }
628
629 pixman_region32_fini(&plane->base.damage);
630 pixman_region32_init(&plane->base.damage);
631
632 if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
633 state->dest_x, state->dest_y)) {
634 weston_log("failed to move cursor: %s\n", strerror(errno));
635 goto err;
636 }
637
638 return;
639
640err:
641 b->cursors_are_broken = 1;
642 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
643}
644
645static int
646drm_output_apply_state_legacy(struct drm_output_state *state)
647{
648 struct drm_output *output = state->output;
649 struct drm_backend *backend = to_drm_backend(output->base.compositor);
650 struct drm_plane *scanout_plane = output->scanout_plane;
651 struct drm_property_info *dpms_prop;
652 struct drm_plane_state *scanout_state;
653 struct drm_mode *mode;
654 struct drm_head *head;
655 const struct pixel_format_info *pinfo = NULL;
656 uint32_t connectors[MAX_CLONED_CONNECTORS];
657 int n_conn = 0;
658 struct timespec now;
659 int ret = 0;
660
661 wl_list_for_each(head, &output->base.head_list, base.output_link) {
662 assert(n_conn < MAX_CLONED_CONNECTORS);
663 connectors[n_conn++] = head->connector_id;
664 }
665
666 /* If disable_planes is set then assign_planes() wasn't
667 * called for this render, so we could still have a stale
668 * cursor plane set up.
669 */
670 if (output->base.disable_planes) {
671 output->cursor_view = NULL;
672 if (output->cursor_plane) {
673 output->cursor_plane->base.x = INT32_MIN;
674 output->cursor_plane->base.y = INT32_MIN;
675 }
676 }
677
678 if (state->dpms != WESTON_DPMS_ON) {
679 if (output->cursor_plane) {
680 ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
681 0, 0, 0);
682 if (ret)
683 weston_log("drmModeSetCursor failed disable: %s\n",
684 strerror(errno));
685 }
686
687 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
688 NULL, 0, NULL);
689 if (ret)
690 weston_log("drmModeSetCrtc failed disabling: %s\n",
691 strerror(errno));
692
693 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
694 weston_compositor_read_presentation_clock(output->base.compositor, &now);
695 drm_output_update_complete(output,
696 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
697 now.tv_sec, now.tv_nsec / 1000);
698
699 return 0;
700 }
701
702 scanout_state =
703 drm_output_state_get_existing_plane(state, scanout_plane);
704
705 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
706 * legacy PageFlip API doesn't allow us to do clipping either. */
707 assert(scanout_state->src_x == 0);
708 assert(scanout_state->src_y == 0);
709 assert(scanout_state->src_w ==
710 (unsigned) (output->base.current_mode->width << 16));
711 assert(scanout_state->src_h ==
712 (unsigned) (output->base.current_mode->height << 16));
713 assert(scanout_state->dest_x == 0);
714 assert(scanout_state->dest_y == 0);
715 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
716 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
717 /* The legacy SetCrtc API doesn't support fences */
718 assert(scanout_state->in_fence_fd == -1);
719
720 mode = to_drm_mode(output->base.current_mode);
721 if (backend->state_invalid ||
722 !scanout_plane->state_cur->fb ||
723 scanout_plane->state_cur->fb->strides[0] !=
724 scanout_state->fb->strides[0]) {
725
726 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
727 scanout_state->fb->fb_id,
728 0, 0,
729 connectors, n_conn,
730 &mode->mode_info);
731 if (ret) {
732 weston_log("set mode failed: %s\n", strerror(errno));
733 goto err;
734 }
735 }
736
737 pinfo = scanout_state->fb->format;
738 drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
739 output->crtc_id, scanout_state->plane->plane_id,
740 pinfo ? pinfo->drm_format_name : "UNKNOWN");
741
742 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
743 scanout_state->fb->fb_id,
744 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
745 weston_log("queueing pageflip failed: %s\n", strerror(errno));
746 goto err;
747 }
748
749 assert(!output->page_flip_pending);
750
751 if (output->pageflip_timer)
752 wl_event_source_timer_update(output->pageflip_timer,
753 backend->pageflip_timeout);
754
755 drm_output_set_cursor(state);
756
757 if (state->dpms != output->state_cur->dpms) {
758 wl_list_for_each(head, &output->base.head_list, base.output_link) {
759 dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
760 if (dpms_prop->prop_id == 0)
761 continue;
762
763 ret = drmModeConnectorSetProperty(backend->drm.fd,
764 head->connector_id,
765 dpms_prop->prop_id,
766 state->dpms);
767 if (ret) {
768 weston_log("DRM: DPMS: failed property set for %s\n",
769 head->base.name);
770 }
771 }
772 }
773
774 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
775
776 return 0;
777
778err:
779 output->cursor_view = NULL;
780 drm_output_state_free(state);
781 return -1;
782}
783
784#ifdef HAVE_DRM_ATOMIC
785static int
786crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
787 enum wdrm_crtc_property prop, uint64_t val)
788{
789 struct drm_property_info *info = &output->props_crtc[prop];
790 int ret;
791
792 if (info->prop_id == 0)
793 return -1;
794
795 ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
796 val);
797 drm_debug(output->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
798 (unsigned long) output->crtc_id,
799 (unsigned long) info->prop_id, info->name,
800 (unsigned long long) val, (unsigned long long) val);
801 return (ret <= 0) ? -1 : 0;
802}
803
804static int
805connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
806 enum wdrm_connector_property prop, uint64_t val)
807{
808 struct drm_property_info *info = &head->props_conn[prop];
809 int ret;
810
811 if (info->prop_id == 0)
812 return -1;
813
814 ret = drmModeAtomicAddProperty(req, head->connector_id,
815 info->prop_id, val);
816 drm_debug(head->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
817 (unsigned long) head->connector_id,
818 (unsigned long) info->prop_id, info->name,
819 (unsigned long long) val, (unsigned long long) val);
820 return (ret <= 0) ? -1 : 0;
821}
822
823static int
824plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
825 enum wdrm_plane_property prop, uint64_t val)
826{
827 struct drm_property_info *info = &plane->props[prop];
828 int ret;
829
830 if (info->prop_id == 0)
831 return -1;
832
833 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
834 val);
835 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
836 (unsigned long) plane->plane_id,
837 (unsigned long) info->prop_id, info->name,
838 (unsigned long long) val, (unsigned long long) val);
839 return (ret <= 0) ? -1 : 0;
840}
841
842
843static int
844plane_add_damage(drmModeAtomicReq *req, struct drm_backend *backend,
845 struct drm_plane_state *plane_state)
846{
847 struct drm_plane *plane = plane_state->plane;
848 struct drm_property_info *info =
849 &plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
850 pixman_box32_t *rects;
851 uint32_t blob_id;
852 int n_rects;
853 int ret;
854
855 if (!pixman_region32_not_empty(&plane_state->damage))
856 return 0;
857
858 /*
859 * If a plane doesn't support fb damage blob property, kernel will
860 * perform full plane update.
861 */
862 if (info->prop_id == 0)
863 return 0;
864
865 rects = pixman_region32_rectangles(&plane_state->damage, &n_rects);
866
867 ret = drmModeCreatePropertyBlob(backend->drm.fd, rects,
868 sizeof(*rects) * n_rects, &blob_id);
869 if (ret != 0)
870 return ret;
871
872 ret = plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS, blob_id);
873 if (ret != 0)
874 return ret;
875
876 return 0;
877}
878
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530879static bool
880drm_head_has_prop(struct drm_head *head,
881 enum wdrm_connector_property prop)
882{
883 if (head && head->props_conn[prop].prop_id != 0)
884 return true;
885
886 return false;
887}
888
889/*
890 * This function converts the protection requests from weston_hdcp_protection
891 * corresponding drm values. These values can be set in "Content Protection"
892 * & "HDCP Content Type" connector properties.
893 */
894static void
895get_drm_protection_from_weston(enum weston_hdcp_protection weston_protection,
896 enum wdrm_content_protection_state *drm_protection,
897 enum wdrm_hdcp_content_type *drm_cp_type)
898{
899
900 switch (weston_protection) {
901 case WESTON_HDCP_DISABLE:
902 *drm_protection = WDRM_CONTENT_PROTECTION_UNDESIRED;
903 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
904 break;
905 case WESTON_HDCP_ENABLE_TYPE_0:
906 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
907 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
908 break;
909 case WESTON_HDCP_ENABLE_TYPE_1:
910 *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
911 *drm_cp_type = WDRM_HDCP_CONTENT_TYPE1;
912 break;
913 default:
914 assert(0 && "bad weston_hdcp_protection");
915 }
916}
917
918static void
919drm_head_set_hdcp_property(struct drm_head *head,
920 enum weston_hdcp_protection protection,
921 drmModeAtomicReq *req)
922{
923 int ret;
924 enum wdrm_content_protection_state drm_protection;
925 enum wdrm_hdcp_content_type drm_cp_type;
926 struct drm_property_enum_info *enum_info;
927 uint64_t prop_val;
928
929 get_drm_protection_from_weston(protection, &drm_protection,
930 &drm_cp_type);
931
932 if (!drm_head_has_prop(head, WDRM_CONNECTOR_CONTENT_PROTECTION))
933 return;
934
935 /*
936 * Content-type property is not exposed for platforms not supporting
937 * HDCP2.2, therefore, type-1 cannot be supported. The type-0 content
938 * still can be supported if the content-protection property is exposed.
939 */
940 if (!drm_head_has_prop(head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE) &&
941 drm_cp_type != WDRM_HDCP_CONTENT_TYPE0)
942 return;
943
944 enum_info = head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION].enum_values;
945 prop_val = enum_info[drm_protection].value;
946 ret = connector_add_prop(req, head, WDRM_CONNECTOR_CONTENT_PROTECTION,
947 prop_val);
948 assert(ret == 0);
949
Ankit Nautiyalfc2c1802019-08-30 19:40:46 +0530950 if (!drm_head_has_prop(head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE))
951 return;
952
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530953 enum_info = head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE].enum_values;
954 prop_val = enum_info[drm_cp_type].value;
955 ret = connector_add_prop(req, head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
956 prop_val);
957 assert(ret == 0);
958}
959
Daniel Stone4c2fc702019-06-18 11:12:07 +0100960static int
961drm_output_apply_state_atomic(struct drm_output_state *state,
962 drmModeAtomicReq *req,
963 uint32_t *flags)
964{
965 struct drm_output *output = state->output;
966 struct drm_backend *b = to_drm_backend(output->base.compositor);
967 struct drm_plane_state *plane_state;
968 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
969 struct drm_head *head;
970 int ret = 0;
971
972 drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
973 (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
974 (unsigned long) output->base.id, output->base.name);
975
976 if (state->dpms != output->state_cur->dpms) {
977 drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
978 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
979 }
980
981 if (state->dpms == WESTON_DPMS_ON) {
982 ret = drm_mode_ensure_blob(b, current_mode);
983 if (ret != 0)
984 return ret;
985
986 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
987 current_mode->blob_id);
988 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
989
990 /* No need for the DPMS property, since it is implicit in
991 * routing and CRTC activity. */
992 wl_list_for_each(head, &output->base.head_list, base.output_link) {
993 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
994 output->crtc_id);
995 }
996 } else {
997 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
998 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
999
1000 /* No need for the DPMS property, since it is implicit in
1001 * routing and CRTC activity. */
1002 wl_list_for_each(head, &output->base.head_list, base.output_link)
1003 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
1004 }
1005
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301006 wl_list_for_each(head, &output->base.head_list, base.output_link)
1007 drm_head_set_hdcp_property(head, state->protection, req);
1008
Daniel Stone4c2fc702019-06-18 11:12:07 +01001009 if (ret != 0) {
1010 weston_log("couldn't set atomic CRTC/connector state\n");
1011 return ret;
1012 }
1013
1014 wl_list_for_each(plane_state, &state->plane_list, link) {
1015 struct drm_plane *plane = plane_state->plane;
1016 const struct pixel_format_info *pinfo = NULL;
1017
1018 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
1019 plane_state->fb ? plane_state->fb->fb_id : 0);
1020 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
1021 plane_state->fb ? output->crtc_id : 0);
1022 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
1023 plane_state->src_x);
1024 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
1025 plane_state->src_y);
1026 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
1027 plane_state->src_w);
1028 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
1029 plane_state->src_h);
1030 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
1031 plane_state->dest_x);
1032 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
1033 plane_state->dest_y);
1034 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
1035 plane_state->dest_w);
1036 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
1037 plane_state->dest_h);
1038 ret |= plane_add_damage(req, b, plane_state);
1039
1040 if (plane_state->fb && plane_state->fb->format)
1041 pinfo = plane_state->fb->format;
1042
1043 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
1044 (unsigned long) plane->plane_id,
1045 pinfo ? pinfo->drm_format_name : "UNKNOWN");
1046
1047 if (plane_state->in_fence_fd >= 0) {
1048 ret |= plane_add_prop(req, plane,
1049 WDRM_PLANE_IN_FENCE_FD,
1050 plane_state->in_fence_fd);
1051 }
1052
Daniel Stone4c2fc702019-06-18 11:12:07 +01001053 if (ret != 0) {
1054 weston_log("couldn't set plane state\n");
1055 return ret;
1056 }
1057 }
1058
1059 return 0;
1060}
1061
1062/**
1063 * Helper function used only by drm_pending_state_apply, with the same
1064 * guarantees and constraints as that function.
1065 */
1066static int
1067drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
1068 enum drm_state_apply_mode mode)
1069{
1070 struct drm_backend *b = pending_state->backend;
1071 struct drm_output_state *output_state, *tmp;
1072 struct drm_plane *plane;
1073 drmModeAtomicReq *req = drmModeAtomicAlloc();
1074 uint32_t flags;
1075 int ret = 0;
1076
1077 if (!req)
1078 return -1;
1079
1080 switch (mode) {
1081 case DRM_STATE_APPLY_SYNC:
1082 flags = 0;
1083 break;
1084 case DRM_STATE_APPLY_ASYNC:
1085 flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
1086 break;
1087 case DRM_STATE_TEST_ONLY:
1088 flags = DRM_MODE_ATOMIC_TEST_ONLY;
1089 break;
1090 }
1091
1092 if (b->state_invalid) {
1093 struct weston_head *head_base;
1094 struct drm_head *head;
1095 uint32_t *unused;
1096 int err;
1097
1098 drm_debug(b, "\t\t[atomic] previous state invalid; "
1099 "starting with fresh state\n");
1100
1101 /* If we need to reset all our state (e.g. because we've
1102 * just started, or just been VT-switched in), explicitly
1103 * disable all the CRTCs and connectors we aren't using. */
1104 wl_list_for_each(head_base,
1105 &b->compositor->head_list, compositor_link) {
1106 struct drm_property_info *info;
1107
1108 if (weston_head_is_enabled(head_base))
1109 continue;
1110
1111 head = to_drm_head(head_base);
1112
1113 drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
1114 head_base->name);
1115
1116 info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
1117 err = drmModeAtomicAddProperty(req, head->connector_id,
1118 info->prop_id, 0);
1119 drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
1120 (unsigned long) head->connector_id,
1121 (unsigned long) info->prop_id,
1122 info->name);
1123 if (err <= 0)
1124 ret = -1;
1125 }
1126
1127 wl_array_for_each(unused, &b->unused_crtcs) {
1128 struct drm_property_info infos[WDRM_CRTC__COUNT];
1129 struct drm_property_info *info;
1130 drmModeObjectProperties *props;
1131 uint64_t active;
1132
1133 memset(infos, 0, sizeof(infos));
1134
1135 /* We can't emit a disable on a CRTC that's already
1136 * off, as the kernel will refuse to generate an event
1137 * for an off->off state and fail the commit.
1138 */
1139 props = drmModeObjectGetProperties(b->drm.fd,
1140 *unused,
1141 DRM_MODE_OBJECT_CRTC);
1142 if (!props) {
1143 ret = -1;
1144 continue;
1145 }
1146
1147 drm_property_info_populate(b, crtc_props, infos,
1148 WDRM_CRTC__COUNT,
1149 props);
1150
1151 info = &infos[WDRM_CRTC_ACTIVE];
1152 active = drm_property_get_value(info, props, 0);
1153 drmModeFreeObjectProperties(props);
1154 if (active == 0) {
1155 drm_property_info_free(infos, WDRM_CRTC__COUNT);
1156 continue;
1157 }
1158
1159 drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
1160 (unsigned long) *unused);
1161
1162 drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
1163 (unsigned long) *unused,
1164 (unsigned long) info->prop_id, info->name);
1165 err = drmModeAtomicAddProperty(req, *unused,
1166 info->prop_id, 0);
1167 if (err <= 0)
1168 ret = -1;
1169
1170 info = &infos[WDRM_CRTC_MODE_ID];
1171 drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
1172 (unsigned long) *unused,
1173 (unsigned long) info->prop_id, info->name);
1174 err = drmModeAtomicAddProperty(req, *unused,
1175 info->prop_id, 0);
1176 if (err <= 0)
1177 ret = -1;
1178
1179 drm_property_info_free(infos, WDRM_CRTC__COUNT);
1180 }
1181
1182 /* Disable all the planes; planes which are being used will
1183 * override this state in the output-state application. */
1184 wl_list_for_each(plane, &b->plane_list, link) {
1185 drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
1186 (unsigned long) plane->plane_id);
1187 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
1188 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
1189 }
1190
1191 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
1192 }
1193
1194 wl_list_for_each(output_state, &pending_state->output_list, link) {
1195 if (output_state->output->virtual)
1196 continue;
1197 if (mode == DRM_STATE_APPLY_SYNC)
1198 assert(output_state->dpms == WESTON_DPMS_OFF);
1199 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
1200 }
1201
1202 if (ret != 0) {
1203 weston_log("atomic: couldn't compile atomic state\n");
1204 goto out;
1205 }
1206
1207 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
1208 drm_debug(b, "[atomic] drmModeAtomicCommit\n");
1209
1210 /* Test commits do not take ownership of the state; return
1211 * without freeing here. */
1212 if (mode == DRM_STATE_TEST_ONLY) {
1213 drmModeAtomicFree(req);
1214 return ret;
1215 }
1216
1217 if (ret != 0) {
1218 weston_log("atomic: couldn't commit new state: %s\n",
1219 strerror(errno));
1220 goto out;
1221 }
1222
1223 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1224 link)
1225 drm_output_assign_state(output_state, mode);
1226
1227 b->state_invalid = false;
1228
1229 assert(wl_list_empty(&pending_state->output_list));
1230
1231out:
1232 drmModeAtomicFree(req);
1233 drm_pending_state_free(pending_state);
1234 return ret;
1235}
1236#endif
1237
1238/**
1239 * Tests a pending state, to see if the kernel will accept the update as
1240 * constructed.
1241 *
1242 * Using atomic modesetting, the kernel performs the same checks as it would
1243 * on a real commit, returning success or failure without actually modifying
1244 * the running state. It does not return -EBUSY if there are pending updates
1245 * in flight, so states may be tested at any point, however this means a
1246 * state which passed testing may fail on a real commit if the timing is not
1247 * respected (e.g. committing before the previous commit has completed).
1248 *
1249 * Without atomic modesetting, we have no way to check, so we optimistically
1250 * claim it will work.
1251 *
1252 * Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
1253 * function does _not_ take ownership of pending_state, nor does it clear
1254 * state_invalid.
1255 */
1256int
1257drm_pending_state_test(struct drm_pending_state *pending_state)
1258{
1259#ifdef HAVE_DRM_ATOMIC
1260 struct drm_backend *b = pending_state->backend;
1261
1262 if (b->atomic_modeset)
1263 return drm_pending_state_apply_atomic(pending_state,
1264 DRM_STATE_TEST_ONLY);
1265#endif
1266
1267 /* We have no way to test state before application on the legacy
1268 * modesetting API, so just claim it succeeded. */
1269 return 0;
1270}
1271
1272/**
1273 * Applies all of a pending_state asynchronously: the primary entry point for
1274 * applying KMS state to a device. Updates the state for all outputs in the
1275 * pending_state, as well as disabling any unclaimed outputs.
1276 *
1277 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1278 */
1279int
1280drm_pending_state_apply(struct drm_pending_state *pending_state)
1281{
1282 struct drm_backend *b = pending_state->backend;
1283 struct drm_output_state *output_state, *tmp;
1284 uint32_t *unused;
1285
1286#ifdef HAVE_DRM_ATOMIC
1287 if (b->atomic_modeset)
1288 return drm_pending_state_apply_atomic(pending_state,
1289 DRM_STATE_APPLY_ASYNC);
1290#endif
1291
1292 if (b->state_invalid) {
1293 /* If we need to reset all our state (e.g. because we've
1294 * just started, or just been VT-switched in), explicitly
1295 * disable all the CRTCs we aren't using. This also disables
1296 * all connectors on these CRTCs, so we don't need to do that
1297 * separately with the pre-atomic API. */
1298 wl_array_for_each(unused, &b->unused_crtcs)
1299 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
1300 NULL);
1301 }
1302
1303 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1304 link) {
1305 struct drm_output *output = output_state->output;
1306 int ret;
1307
1308 if (output->virtual) {
1309 drm_output_assign_state(output_state,
1310 DRM_STATE_APPLY_ASYNC);
1311 continue;
1312 }
1313
1314 ret = drm_output_apply_state_legacy(output_state);
1315 if (ret != 0) {
1316 weston_log("Couldn't apply state for output %s\n",
1317 output->base.name);
1318 }
1319 }
1320
1321 b->state_invalid = false;
1322
1323 assert(wl_list_empty(&pending_state->output_list));
1324
1325 drm_pending_state_free(pending_state);
1326
1327 return 0;
1328}
1329
1330/**
1331 * The synchronous version of drm_pending_state_apply. May only be used to
1332 * disable outputs. Does so synchronously: the request is guaranteed to have
1333 * completed on return, and the output will not be touched afterwards.
1334 *
1335 * Unconditionally takes ownership of pending_state, and clears state_invalid.
1336 */
1337int
1338drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
1339{
1340 struct drm_backend *b = pending_state->backend;
1341 struct drm_output_state *output_state, *tmp;
1342 uint32_t *unused;
1343
1344#ifdef HAVE_DRM_ATOMIC
1345 if (b->atomic_modeset)
1346 return drm_pending_state_apply_atomic(pending_state,
1347 DRM_STATE_APPLY_SYNC);
1348#endif
1349
1350 if (b->state_invalid) {
1351 /* If we need to reset all our state (e.g. because we've
1352 * just started, or just been VT-switched in), explicitly
1353 * disable all the CRTCs we aren't using. This also disables
1354 * all connectors on these CRTCs, so we don't need to do that
1355 * separately with the pre-atomic API. */
1356 wl_array_for_each(unused, &b->unused_crtcs)
1357 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
1358 NULL);
1359 }
1360
1361 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1362 link) {
1363 int ret;
1364
1365 assert(output_state->dpms == WESTON_DPMS_OFF);
1366 ret = drm_output_apply_state_legacy(output_state);
1367 if (ret != 0) {
1368 weston_log("Couldn't apply state for output %s\n",
1369 output_state->output->base.name);
1370 }
1371 }
1372
1373 b->state_invalid = false;
1374
1375 assert(wl_list_empty(&pending_state->output_list));
1376
1377 drm_pending_state_free(pending_state);
1378
1379 return 0;
1380}
1381
1382void
1383drm_output_update_msc(struct drm_output *output, unsigned int seq)
1384{
1385 uint64_t msc_hi = output->base.msc >> 32;
1386
1387 if (seq < (output->base.msc & 0xffffffff))
1388 msc_hi++;
1389
1390 output->base.msc = (msc_hi << 32) + seq;
1391}
1392
1393static void
1394page_flip_handler(int fd, unsigned int frame,
1395 unsigned int sec, unsigned int usec, void *data)
1396{
1397 struct drm_output *output = data;
1398 struct drm_backend *b = to_drm_backend(output->base.compositor);
1399 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1400 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1401 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1402
1403 drm_output_update_msc(output, frame);
1404
1405 assert(!b->atomic_modeset);
1406 assert(output->page_flip_pending);
1407 output->page_flip_pending = 0;
1408
1409 drm_output_update_complete(output, flags, sec, usec);
1410}
1411
1412#ifdef HAVE_DRM_ATOMIC
1413static void
1414atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
1415 unsigned int usec, unsigned int crtc_id, void *data)
1416{
1417 struct drm_backend *b = data;
1418 struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
1419 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1420 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1421 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
1422
1423 /* During the initial modeset, we can disable CRTCs which we don't
1424 * actually handle during normal operation; this will give us events
1425 * for unknown outputs. Ignore them. */
1426 if (!output || !output->base.enabled)
1427 return;
1428
1429 drm_output_update_msc(output, frame);
1430
1431 drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id);
1432 assert(b->atomic_modeset);
1433 assert(output->atomic_complete_pending);
1434 output->atomic_complete_pending = 0;
1435
1436 drm_output_update_complete(output, flags, sec, usec);
1437 drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
1438}
1439#endif
1440
1441int
1442on_drm_input(int fd, uint32_t mask, void *data)
1443{
1444#ifdef HAVE_DRM_ATOMIC
1445 struct drm_backend *b = data;
1446#endif
1447 drmEventContext evctx;
1448
1449 memset(&evctx, 0, sizeof evctx);
1450#ifndef HAVE_DRM_ATOMIC
1451 evctx.version = 2;
1452#else
1453 evctx.version = 3;
1454 if (b->atomic_modeset)
1455 evctx.page_flip_handler2 = atomic_flip_handler;
1456 else
1457#endif
1458 evctx.page_flip_handler = page_flip_handler;
1459 drmHandleEvent(fd, &evctx);
1460
1461 return 1;
1462}
1463
1464int
1465init_kms_caps(struct drm_backend *b)
1466{
1467 uint64_t cap;
1468 int ret;
1469 clockid_t clk_id;
1470
1471 weston_log("using %s\n", b->drm.filename);
1472
1473 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1474 if (ret == 0 && cap == 1)
1475 clk_id = CLOCK_MONOTONIC;
1476 else
1477 clk_id = CLOCK_REALTIME;
1478
1479 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
1480 weston_log("Error: failed to set presentation clock %d.\n",
1481 clk_id);
1482 return -1;
1483 }
1484
1485 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
1486 if (ret == 0)
1487 b->cursor_width = cap;
1488 else
1489 b->cursor_width = 64;
1490
1491 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1492 if (ret == 0)
1493 b->cursor_height = cap;
1494 else
1495 b->cursor_height = 64;
1496
1497 if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
1498 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1499 b->universal_planes = (ret == 0);
1500 }
1501 weston_log("DRM: %s universal planes\n",
1502 b->universal_planes ? "supports" : "does not support");
1503
1504#ifdef HAVE_DRM_ATOMIC
1505 if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
1506 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
1507 if (ret != 0)
1508 cap = 0;
1509 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
1510 b->atomic_modeset = ((ret == 0) && (cap == 1));
1511 }
1512#endif
1513 weston_log("DRM: %s atomic modesetting\n",
1514 b->atomic_modeset ? "supports" : "does not support");
1515
1516#ifdef HAVE_DRM_ADDFB2_MODIFIERS
1517 ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
1518 if (ret == 0)
1519 b->fb_modifiers = cap;
1520 else
1521#endif
1522 b->fb_modifiers = 0;
1523
1524 /*
1525 * KMS support for hardware planes cannot properly synchronize
1526 * without nuclear page flip. Without nuclear/atomic, hw plane
1527 * and cursor plane updates would either tear or cause extra
1528 * waits for vblanks which means dropping the compositor framerate
1529 * to a fraction. For cursors, it's not so bad, so they are
1530 * enabled.
1531 */
1532 if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
1533 b->sprites_are_broken = 1;
1534
1535 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
1536 b->aspect_ratio_supported = (ret == 0);
1537 weston_log("DRM: %s picture aspect ratio\n",
1538 b->aspect_ratio_supported ? "supports" : "does not support");
1539
1540 return 0;
1541}