llimphi_raster/lib.rs
1//! llimphi-raster — Brocha Matemática.
2//!
3//! Traduce primitivas vectoriales (líneas, curvas de Bézier, texto) a
4//! píxeles via Compute Shaders. Backend: `vello`.
5//!
6//! Punto de entrada: [`Renderer`]. Recibe una [`vello::Scene`] y la pinta
7//! sobre un [`llimphi_hal::Frame`].
8
9use llimphi_hal::{Frame, Hal};
10pub use vello;
11pub use vello::kurbo;
12pub use vello::peniko;
13// Renderer "hybrid" CPU+GPU sin compute shaders (feature `hybrid`):
14// vello 0.7 trae `vello_hybrid::Renderer` como alternativa al `vello::Renderer`
15// estándar — sin compute, mejor compat WebGL2 + Adreno/Mali viejas. Lo
16// re-exportamos cuando la feature está activa para que apps avanzadas (web,
17// móvil entry-level) puedan instanciarlo sin agregar otra dep.
18#[cfg(feature = "hybrid")]
19pub use vello_hybrid;
20
21pub mod gpu;
22pub use gpu::{GpuBatch, GpuPipelines};
23
24/// Errores del rasterizador.
25#[derive(Debug)]
26pub enum RasterError {
27 Init(String),
28 Render(String),
29}
30
31impl std::fmt::Display for RasterError {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 match self {
34 Self::Init(s) => write!(f, "vello init: {s}"),
35 Self::Render(s) => write!(f, "vello render: {s}"),
36 }
37 }
38}
39
40impl std::error::Error for RasterError {}
41
42/// Rasterizador vectorial. Una instancia por surface (porque vello cachea
43/// resources contra un `surface_format` específico).
44pub struct Renderer {
45 inner: vello::Renderer,
46}
47
48impl Renderer {
49 /// Inicializa el rasterizador. Vello acepta cualquier textura compatible
50 /// (Rgba8Unorm / Bgra8Unorm) en `render`, así que no se fija un formato
51 /// en construcción.
52 ///
53 /// **`antialiasing_support`**: pedimos `area` solamente, no `all()`.
54 /// `area` es el único método que `render()` usa (`AaConfig::Area`
55 /// fijo). Pedir `all()` haría a vello compilar también pipelines
56 /// para `msaa8` y `msaa16` que nunca se invocan — en Mali-G57 eso
57 /// triplica el cold-start (medido: 3.7s vs ~1.2s). Si alguna app
58 /// futura necesita MSAA, agregamos un constructor explícito.
59 ///
60 /// **`num_init_threads: None`**: vello paraleliza la compilación
61 /// de shaders en `None` → todos los CPU cores. Mali-G57 viene en
62 /// SoCs octa-core ARM; con 1 thread tardamos 2.0s, con 8 esperamos
63 /// ~400-600ms. La compilación de shaders es 100% CPU (Rust →
64 /// SPIR-V), el GPU no participa, así que multi-thread escala
65 /// casi linealmente hasta saturar el queue del Naga compiler.
66 pub fn new(hal: &Hal) -> Result<Self, RasterError> {
67 let inner = vello::Renderer::new(
68 &hal.device,
69 vello::RendererOptions {
70 use_cpu: false,
71 antialiasing_support: vello::AaSupport {
72 area: true,
73 msaa8: false,
74 msaa16: false,
75 },
76 num_init_threads: None,
77 pipeline_cache: None,
78 },
79 )
80 .map_err(|e| RasterError::Init(e.to_string()))?;
81 Ok(Self { inner })
82 }
83
84 /// Renderiza `scene` sobre `frame` limpiando con `base_color`. AA fija
85 /// en area-sampling (precisión Δ < 10⁻⁹ rad del SDD).
86 pub fn render(
87 &mut self,
88 hal: &Hal,
89 scene: &vello::Scene,
90 frame: &Frame,
91 base_color: peniko::Color,
92 ) -> Result<(), RasterError> {
93 let (width, height) = frame.size();
94 self.render_to_view(hal, scene, frame.view(), width, height, base_color)
95 }
96
97 /// Como [`render`](Self::render) pero contra una vista de textura
98 /// explícita (mismo formato/tamaño que la intermedia). Lo usa el
99 /// compositor de overlay de `llimphi-ui` para rasterizar la capa de
100 /// overlay sobre fondo transparente en su propia textura. Ojo:
101 /// `render_to_texture` **limpia** el target con `base_color` y escribe
102 /// todos los píxeles — no compone sobre contenido previo.
103 pub fn render_to_view(
104 &mut self,
105 hal: &Hal,
106 scene: &vello::Scene,
107 view: &llimphi_hal::wgpu::TextureView,
108 width: u32,
109 height: u32,
110 base_color: peniko::Color,
111 ) -> Result<(), RasterError> {
112 self.inner
113 .render_to_texture(
114 &hal.device,
115 &hal.queue,
116 scene,
117 view,
118 &vello::RenderParams {
119 base_color,
120 width,
121 height,
122 antialiasing_method: vello::AaConfig::Area,
123 },
124 )
125 .map_err(|e| RasterError::Render(e.to_string()))
126 }
127}