Skip to main content

drmkit_cursor/
size.rs

1// SPDX-FileCopyrightText: (c) 2026 Joel Winarske
2// SPDX-License-Identifier: MIT
3
4//! How big the cursor buffer is.
5//!
6//! Two decisions. What size to ask for, which depends on the path and what the
7//! driver advertises; and what size to settle on, which depends on what the
8//! kernel will actually accept. The second needs a device, so it takes the
9//! probe as a parameter and everything here stays testable.
10
11use crate::plane::PlanePath;
12
13/// What every driver hard-codes for `drmModeSetCursor`, and the floor
14/// everywhere else.
15///
16/// The legacy call has no capability query, so there is nothing to ask.
17const LEGACY_SIZE: u32 = 64;
18
19/// Sizes worth probing, largest first.
20///
21/// Not a range: these are the sizes real hardware implements. i915 does 64,
22/// amdgpu 256, and asking for anything between them gets rounded or refused
23/// depending on the driver, so there is no point walking one pixel at a time.
24const LADDER: [u32; 3] = [256, 128, 64];
25
26/// The size to ask for, before finding out what is accepted.
27///
28/// A caller who names a size gets it considered as-is. Otherwise the atomic
29/// paths take what the driver advertises through `DRM_CAP_CURSOR_WIDTH`, so a
30/// plane that wants 256 gets 256; legacy takes 64, because that is what the
31/// call means.
32#[must_use]
33pub fn preferred_size(requested: u32, path: PlanePath, driver_cap: Option<u32>) -> u32 {
34    if requested != 0 {
35        return requested;
36    }
37    match path {
38        PlanePath::Legacy => LEGACY_SIZE,
39        PlanePath::AtomicCursor | PlanePath::AtomicOverlay => {
40            driver_cap.filter(|cap| *cap != 0).unwrap_or(LEGACY_SIZE)
41        }
42    }
43}
44
45/// Settle on a buffer size, asking `accepts` what the kernel will take.
46///
47/// Walks the ladder downward from `preferred`, and never above it: a caller
48/// who asked for a small cursor does not get a large one because the driver
49/// could manage it.
50///
51/// When nothing is accepted the answer is `preferred`, floored at 64 — there
52/// has to be a buffer either way, and the first real commit will surface the
53/// kernel's objection if there is one. That case is usually not about size at
54/// all: with no mode set yet, every `TEST_ONLY` fails for unrelated reasons.
55pub fn probe_size(preferred: u32, mut accepts: impl FnMut(u32) -> bool) -> u32 {
56    for candidate in LADDER {
57        if candidate <= preferred && accepts(candidate) {
58            return candidate;
59        }
60    }
61    preferred.max(LEGACY_SIZE)
62}