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