smudge_platform/renderer.rs
1//! The renderer a window presents with, and the environment override on it.
2
3use std::env;
4
5use crate::error::PlatformError;
6
7/// The environment variable that overrides the renderer choice.
8///
9/// Its value is `cpu`, `gpu` or `auto`. Setting it lets a machine switch
10/// renderer without a rebuild, which is how a check of the automatic choice
11/// runs on a machine with only a software adapter.
12pub const RENDERER_ENVIRONMENT: &str = "SMUDGE_RENDERER";
13
14/// Which renderer a window presents with.
15///
16/// The CPU renderer keeps a pixmap and repaints only the frame's damage. The
17/// GPU renderer draws the whole frame on every present, with no damage
18/// tracking. Both draw the same display list.
19#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
20pub enum RendererChoice {
21 /// The CPU renderer. Always available.
22 Cpu,
23 /// The GPU renderer through vello.
24 ///
25 /// Needs the `gpu` feature and an adapter that can present to the window.
26 /// A run with this choice fails when either is missing; it never falls
27 /// back on its own.
28 Gpu,
29 /// The GPU renderer when the window's adapter is a real GPU, and the CPU
30 /// renderer otherwise: when the adapter is a software rasterizer such as
31 /// llvmpipe or SwiftShader, when no adapter exists, when the window
32 /// surface cannot present GPU frames, or while the damage overlay is on.
33 /// The default in builds with the `gpu` feature.
34 Auto,
35}
36
37impl Default for RendererChoice {
38 fn default() -> RendererChoice {
39 // The default depends on the feature: `Auto` with the gpu feature and
40 // `Cpu` without it, which a derive cannot switch by feature.
41 if cfg!(feature = "gpu") {
42 RendererChoice::Auto
43 } else {
44 RendererChoice::Cpu
45 }
46 }
47}
48
49impl RendererChoice {
50 /// Returns the choice with the environment override applied.
51 ///
52 /// [`RENDERER_ENVIRONMENT`], when it holds `cpu`, `gpu` or `auto`,
53 /// replaces this choice; any other non-empty value fails the run, and an
54 /// unset or empty variable leaves the choice alone.
55 ///
56 /// # Errors
57 ///
58 /// Returns [`PlatformError::Renderer`] when the environment variable
59 /// holds an unknown value.
60 pub(crate) fn with_env_override(self) -> Result<RendererChoice, PlatformError> {
61 let value = env::var(RENDERER_ENVIRONMENT).ok();
62 match env_choice(value.as_deref()) {
63 Ok(Some(overridden)) => Ok(overridden),
64 Ok(None) => Ok(self),
65 Err(value) => Err(PlatformError::Renderer(format!(
66 "{RENDERER_ENVIRONMENT} is set to {value:?}; expected cpu, gpu or auto"
67 ))),
68 }
69 }
70}
71
72/// Parses one override value, or `None` when the variable is unset or empty.
73fn env_choice(value: Option<&str>) -> Result<Option<RendererChoice>, String> {
74 match value {
75 None | Some("") => Ok(None),
76 Some("cpu") => Ok(Some(RendererChoice::Cpu)),
77 Some("gpu") => Ok(Some(RendererChoice::Gpu)),
78 Some("auto") => Ok(Some(RendererChoice::Auto)),
79 Some(other) => Err(String::from(other)),
80 }
81}
82
83#[cfg(test)]
84#[path = "renderer_tests.rs"]
85mod tests;