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