use iris::{ layout::Ui, render::{UiLimits, UiRenderer}, }; use pollster::FutureExt; use std::sync::Arc; use wgpu::{util::StagingBelt, *}; use winit::{dpi::PhysicalSize, window::Window}; pub const CLEAR_COLOR: Color = Color::BLACK; pub struct Renderer { window: Arc, surface: Surface<'static>, device: Device, queue: Queue, config: SurfaceConfiguration, encoder: CommandEncoder, staging_belt: StagingBelt, pub ui: UiRenderer, } impl Renderer { pub fn update(&mut self, updates: &mut Ui) { self.ui.update(&self.device, &self.queue, updates); } pub fn draw(&mut self) { let output = self.surface.get_current_texture().unwrap(); let view = output .texture .create_view(&TextureViewDescriptor::default()); let mut encoder = std::mem::replace(&mut self.encoder, Self::create_encoder(&self.device)); { let render_pass = &mut encoder.begin_render_pass(&RenderPassDescriptor { color_attachments: &[Some(RenderPassColorAttachment { view: &view, resolve_target: None, ops: Operations { load: LoadOp::Clear(CLEAR_COLOR), store: StoreOp::Store, }, depth_slice: None, })], ..Default::default() }); self.ui.draw(render_pass); } self.queue.submit(std::iter::once(encoder.finish())); self.staging_belt.finish(); output.present(); self.staging_belt.recall(); } pub fn resize(&mut self, size: &PhysicalSize) { self.config.width = size.width; self.config.height = size.height; self.surface.configure(&self.device, &self.config); self.ui.resize(size, &self.queue); } fn create_encoder(device: &Device) -> CommandEncoder { device.create_command_encoder(&CommandEncoderDescriptor { label: Some("Render Encoder"), }) } pub fn new(window: Arc) -> Self { let size = window.inner_size(); let instance = Instance::new(&InstanceDescriptor { backends: Backends::PRIMARY, ..Default::default() }); let surface = instance .create_surface(window.clone()) .expect("Could not create window surface!"); let adapter = instance .request_adapter(&RequestAdapterOptions { power_preference: PowerPreference::default(), compatible_surface: Some(&surface), force_fallback_adapter: false, }) .block_on() .expect("Could not get adapter!"); let ui_limits = UiLimits::default(); let (device, queue) = adapter .request_device(&DeviceDescriptor { required_features: Features::TEXTURE_BINDING_ARRAY | Features::PARTIALLY_BOUND_BINDING_ARRAY | Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, required_limits: Limits { max_binding_array_elements_per_shader_stage: ui_limits .max_binding_array_elements_per_shader_stage(), max_binding_array_sampler_elements_per_shader_stage: ui_limits .max_binding_array_sampler_elements_per_shader_stage(), ..Default::default() }, ..Default::default() }) .block_on() .expect("Could not get device!"); let surface_caps = surface.get_capabilities(&adapter); let surface_format = surface_caps .formats .iter() .copied() .find(|f| f.is_srgb()) .unwrap_or(surface_caps.formats[0]); let config = SurfaceConfiguration { usage: TextureUsages::RENDER_ATTACHMENT, format: surface_format, width: size.width, height: size.height, present_mode: PresentMode::AutoVsync, alpha_mode: surface_caps.alpha_modes[0], desired_maximum_frame_latency: 2, view_formats: vec![], }; surface.configure(&device, &config); let staging_belt = StagingBelt::new(4096 * 4); let encoder = Self::create_encoder(&device); let shape_pipeline = UiRenderer::new(&device, &queue, &config, ui_limits); Self { surface, device, queue, config, encoder, staging_belt, ui: shape_pipeline, window, } } pub fn window(&self) -> &Window { self.window.as_ref() } }