#![allow(
dead_code,
reason = "This is a shared module between examples; not all examples use all functionality from it"
)]
use winit::window::Window;
use vello_hybrid::{RenderTargetConfig, Renderer};
use wgpu::{
Adapter, Device, Features, Instance, Limits, MemoryHints, Queue, Surface, SurfaceConfiguration,
SurfaceTarget, TextureFormat,
};
use winit::event_loop::ActiveEventLoop;
pub(crate) fn create_winit_window(
event_loop: &dyn ActiveEventLoop,
width: u32,
height: u32,
initially_visible: bool,
) -> Box<dyn Window> {
let attr = <dyn Window>::default_attributes()
.with_surface_size(winit::dpi::PhysicalSize::new(width, height))
.with_resizable(true)
.with_title("Vello SVG Renderer")
.with_visible(initially_visible)
.with_active(true);
event_loop.create_window(attr).unwrap()
}
pub(crate) fn create_vello_renderer(
render_cx: &RenderContext,
surface: &RenderSurface<'_>,
) -> Renderer {
Renderer::new(
&render_cx.devices[surface.dev_id].device,
&RenderTargetConfig {
format: surface.config.format,
width: surface.config.width,
height: surface.config.height,
},
)
}
#[derive(Debug)]
pub(crate) struct RenderContext {
pub(crate) instance: Instance,
pub(crate) devices: Vec<DeviceHandle>,
}
#[derive(Debug)]
pub(crate) struct DeviceHandle {
pub(crate) adapter: Adapter,
pub(crate) device: Device,
pub(crate) queue: Queue,
}
impl RenderContext {
pub(crate) fn new() -> Self {
let backends = wgpu::Backends::from_env().unwrap_or_default();
let flags = wgpu::InstanceFlags::from_build_config().with_env();
let backend_options = wgpu::BackendOptions::from_env_or_default();
let instance = Instance::new(&wgpu::InstanceDescriptor {
backends,
flags,
backend_options,
});
Self {
instance,
devices: Vec::new(),
}
}
pub(crate) async fn create_surface<'w>(
&mut self,
window: impl Into<SurfaceTarget<'w>>,
width: u32,
height: u32,
present_mode: wgpu::PresentMode,
format: TextureFormat,
) -> RenderSurface<'w> {
self.create_render_surface(
self.instance
.create_surface(window.into())
.expect("Error creating surface"),
width,
height,
present_mode,
format,
)
.await
}
pub(crate) async fn create_render_surface<'w>(
&mut self,
surface: Surface<'w>,
width: u32,
height: u32,
present_mode: wgpu::PresentMode,
format: TextureFormat,
) -> RenderSurface<'w> {
let dev_id = self
.device(Some(&surface))
.await
.expect("No compatible device");
let config = SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format,
width,
height,
present_mode,
desired_maximum_frame_latency: 2,
alpha_mode: wgpu::CompositeAlphaMode::Auto,
view_formats: vec![],
};
let surface = RenderSurface {
surface,
config,
dev_id,
};
self.configure_surface(&surface);
surface
}
pub(crate) fn resize_surface(&self, surface: &mut RenderSurface<'_>, width: u32, height: u32) {
surface.config.width = width;
surface.config.height = height;
self.configure_surface(surface);
}
pub(crate) fn set_present_mode(
&self,
surface: &mut RenderSurface<'_>,
present_mode: wgpu::PresentMode,
) {
surface.config.present_mode = present_mode;
self.configure_surface(surface);
}
fn configure_surface(&self, surface: &RenderSurface<'_>) {
let device = &self.devices[surface.dev_id].device;
surface.surface.configure(device, &surface.config);
}
pub(crate) async fn device(
&mut self,
compatible_surface: Option<&Surface<'_>>,
) -> Option<usize> {
let compatible = match compatible_surface {
Some(s) => self
.devices
.iter()
.enumerate()
.find(|(_, d)| d.adapter.is_surface_supported(s))
.map(|(i, _)| i),
None => (!self.devices.is_empty()).then_some(0),
};
if compatible.is_none() {
return self.new_device(compatible_surface).await;
}
compatible
}
async fn new_device(&mut self, compatible_surface: Option<&Surface<'_>>) -> Option<usize> {
let adapter =
wgpu::util::initialize_adapter_from_env_or_default(&self.instance, compatible_surface)
.await?;
let limits = Limits::default();
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
required_features: Features::empty(),
required_limits: limits,
memory_hints: MemoryHints::default(),
},
None,
)
.await
.ok()?;
let device_handle = DeviceHandle {
adapter,
device,
queue,
};
self.devices.push(device_handle);
Some(self.devices.len() - 1)
}
}
#[derive(Debug)]
pub(crate) struct RenderSurface<'s> {
pub(crate) surface: Surface<'s>,
pub(crate) config: SurfaceConfiguration,
pub(crate) dev_id: usize,
}