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