use std::sync::Arc; use std::{iter, num::NonZeroU32, ops::Range, rc::Rc}; use bytemuck::__core::mem; use bytemuck::{Pod, Zeroable}; use cgmath::Point3; use futures::executor::LocalPool; use legion::world::SubWorld; use legion::*; use wgpu::util::DeviceExt; use wgpu::{ BindGroup, BindGroupLayout, Buffer, Device, Instance, Queue, Surface, SwapChain, SwapChainDescriptor, SwapChainFrame, TextureView, }; use winit::dpi::PhysicalSize; use winit::platform::unix::x11::ffi::Time; use winit::window::Window; use crate::geometry::{create_plane, import_mesh, vertex, Vertex}; use crate::light::LightRaw; use crate::{Color, DirectionalLight, Mesh, Position, RangeCopy, Velocity, OPENGL_TO_WGPU_MATRIX}; #[repr(C)] #[derive(Clone, Copy)] pub struct ForwardUniforms { proj: [[f32; 4]; 4], num_lights: [u32; 4], } unsafe impl Pod for ForwardUniforms {} unsafe impl Zeroable for ForwardUniforms {} #[repr(C)] #[derive(Clone, Copy)] pub struct EntityUniforms { model: [[f32; 4]; 4], color: [f32; 4], } unsafe impl Pod for EntityUniforms {} unsafe impl Zeroable for EntityUniforms {} #[repr(C)] pub struct ShadowUniforms { proj: [[f32; 4]; 4], } pub struct Pass { pipeline: wgpu::RenderPipeline, bind_group: wgpu::BindGroup, uniform_buf: wgpu::Buffer, } pub struct Renderer { pub window: Window, swapchain: SwapChain, swapchain_description: Arc, instance: Arc, device: Arc, queue: Arc, size: PhysicalSize, surface: Arc, lights_are_dirty: bool, shadow_pass: Pass, forward_pass: Pass, forward_depth: wgpu::TextureView, entity_bind_group_layout: BindGroupLayout, shadow_target_views: Vec>, views_given: u32, light_uniform_buf: wgpu::Buffer, } impl Renderer { const MAX_LIGHTS: usize = 10; const SHADOW_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; const SHADOW_SIZE: wgpu::Extent3d = wgpu::Extent3d { width: 512, height: 512, depth: Self::MAX_LIGHTS as u32, }; const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; pub(crate) fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4 { let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 20.0); let mx_view = cgmath::Matrix4::look_at( cgmath::Point3::new(3.0f32, -10.0, 6.0), cgmath::Point3::new(0f32, 0.0, 0.0), cgmath::Vector3::unit_z(), ); let mx_correction = OPENGL_TO_WGPU_MATRIX; mx_correction * mx_projection * mx_view } } #[system] #[write_component(Position)] #[write_component(Point3)] #[write_component(Mesh)] #[write_component(Color)] #[write_component(DirectionalLight)] pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { let mut encoder = renderer .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); encoder.push_debug_group("start render function"); let frame = renderer.get_current_frame(); let mut query = <(&mut Position, &mut Mesh, &mut Color)>::query(); let mut mesh_stack = Vec::new(); // Update the entity uniforms for (pos, mesh, color) in query.iter_mut(world) { // let rotation = cgmath::Matrix4::from_angle_x(cgmath::Deg(1.0)); // pos.mx = pos.mx * rotation; let data = EntityUniforms { model: pos.mx.into(), color: [ color.r as f32, color.g as f32, color.b as f32, color.a as f32, ], }; renderer .queue .write_buffer(&mesh.uniform_buffer, 0, bytemuck::bytes_of(&data)); mesh_stack.push(mesh.clone()); } if renderer.lights_are_dirty { //renderer.lights_are_dirty = false; let mut query = <(&mut DirectionalLight, &mut Position)>::query(); for (i, (light, pos)) in query.iter_mut(world).enumerate() { renderer.queue.write_buffer( &renderer.light_uniform_buf, (i * mem::size_of::()) as wgpu::BufferAddress, bytemuck::bytes_of(&light.to_raw(*pos)), ); } } encoder.push_debug_group("shadow passes"); let mut query = <(&mut DirectionalLight, &mut Point3)>::query(); for (i, (light, pos)) in query.iter_mut(world).enumerate() { encoder.insert_debug_marker(&format!("shadow pass {} (light at position {:?})", i, pos)); // The light uniform buffer already has the projection, // let's just copy it over to the shadow uniform buffer. encoder.copy_buffer_to_buffer( &renderer.light_uniform_buf, (i * mem::size_of::()) as wgpu::BufferAddress, &renderer.shadow_pass.uniform_buf, 0, 64, ); encoder.insert_debug_marker("render entities"); let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &[], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { attachment: &light.target_view, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear(1.0), store: true, }), stencil_ops: None, }), }); pass.set_pipeline(&renderer.shadow_pass.pipeline); pass.set_bind_group(0, &renderer.shadow_pass.bind_group, &[]); for mesh in &mesh_stack { pass.set_bind_group(1, &mesh.bind_group, &[]); pass.set_index_buffer(mesh.index_buffer.slice(..)); pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); } } encoder.pop_debug_group(); // forward pass encoder.push_debug_group("forward rendering pass"); { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { attachment: &frame.output.view, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear(wgpu::Color { r: 0.1, g: 0.2, b: 0.3, a: 1.0, }), store: true, }, }], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { attachment: &renderer.forward_depth, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear(1.0), store: false, }), stencil_ops: None, }), }); pass.set_pipeline(&renderer.forward_pass.pipeline); pass.set_bind_group(0, &renderer.forward_pass.bind_group, &[]); let mut query = <(&mut Position, &mut Mesh, &mut Color)>::query(); for (pos, mesh, color) in query.iter_mut(world) { pass.set_bind_group(1, &mesh.bind_group, &[]); pass.set_index_buffer(mesh.index_buffer.slice(..)); pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); } } encoder.pop_debug_group(); encoder.pop_debug_group(); renderer.queue.submit(iter::once(encoder.finish())); } impl Renderer { pub fn get_current_frame(&mut self) -> SwapChainFrame { // Update the renderers swapchain state match self.swapchain.get_current_frame() { Ok(frame) => frame, Err(_) => { self.swapchain = self .device .create_swap_chain(&self.surface, &self.swapchain_description); self.swapchain .get_current_frame() .expect("Failed to acquire next swap chain texture!") } } } pub fn create_buffer( device: &wgpu::Device, indices: Vec, vertices: Vec, ) -> (Arc, Arc) { let vertex_buf = Arc::new( device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("vertex-buffer"), contents: bytemuck::cast_slice(&vertices), usage: wgpu::BufferUsage::VERTEX, }), ); let index_buf = Arc::new( device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("index-buffer"), contents: bytemuck::cast_slice(&indices), usage: wgpu::BufferUsage::INDEX, }), ); (vertex_buf, index_buf) } pub fn create_light(&mut self) -> DirectionalLight { let target = self.shadow_target_views.get(self.views_given as usize).take().unwrap(); self.views_given = self.views_given + 1; DirectionalLight { color: wgpu::Color { r: 1.0, g: 0.5, b: 0.5, a: 1.0, }, fov: 45.0, depth: RangeCopy { start: 1.0, end: 20.0, }, target_view: target.clone(), } } pub fn create_plane(&self, size: f32) -> Mesh { let vertices = [ vertex([size, -size, 0.0], [0.0, 0.0, 1.0]), vertex([size, size, 0.0], [0.0, 0.0, 1.0]), vertex([-size, -size, 0.0], [0.0, 0.0, 1.0]), vertex([-size, size, 0.0], [0.0, 0.0, 1.0]), ]; let indices: &[u32] = &[0, 1, 2, 2, 1, 3]; let index_count = indices.len(); let (vertex_buf, index_buf) = Renderer::create_buffer(&self.device, indices.to_vec(), vertices.to_vec()); let uniform_buf = Arc::new(self.device.create_buffer(&wgpu::BufferDescriptor { label: Some("Plane Uniform Buf"), size: mem::size_of::() as wgpu::BufferAddress, usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, mapped_at_creation: false, })); let bind_group = Arc::new(self.device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &self.entity_bind_group_layout, entries: &[wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)), }], label: Some("Plane Bind Group"), })); Mesh { index_buffer: index_buf, index_count: index_count, vertex_buffer: vertex_buf, uniform_buffer: uniform_buf, bind_group: bind_group, } } pub fn load_mesh_to_buffer(&self, filepath: &str) -> Mesh { let (vertices, indices) = import_mesh(filepath); let index_count = indices.len(); let (vertex_buf, index_buf) = Renderer::create_buffer(&self.device, indices, vertices); let uniform_buf = Arc::new(self.device.create_buffer(&wgpu::BufferDescriptor { label: Some("Mesh Uniform Buf"), size: mem::size_of::() as wgpu::BufferAddress, usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, mapped_at_creation: false, })); let bind_group = Arc::new(self.device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &self.entity_bind_group_layout, entries: &[wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)), }], label: Some("Mesh Bind Group"), })); Mesh { index_buffer: index_buf, index_count: index_count, vertex_buffer: vertex_buf, uniform_buffer: uniform_buf, bind_group: bind_group, } } pub fn init(window: Window) -> Renderer { log::info!("Initializing the surface..."); // Grab the GPU instance, and query its features let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); let (size, surface) = unsafe { let size = window.inner_size(); let surface = instance.create_surface(&window); (size, surface) }; let surface = Arc::new(surface); let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::HighPerformance, compatible_surface: Some(&surface), }); let adapter = futures::executor::block_on(adapter).unwrap(); let optional_features = Renderer::optional_features(); let required_features = Renderer::required_features(); let adapter_features = adapter.features(); let needed_limits = wgpu::Limits::default(); //Renderer::required_limits(); // Maybe for debug tracing??? let trace_dir = std::env::var("WGPU_TRACE"); // And then get the device we want let device = adapter.request_device( &wgpu::DeviceDescriptor { features: (optional_features & adapter_features) | required_features, limits: needed_limits, shader_validation: true, }, trace_dir.ok().as_ref().map(std::path::Path::new), ); let (device, queue) = futures::executor::block_on(device).unwrap(); let queue = Arc::new(queue); let device = Arc::new(device); // This is some gross-ass web shit /*#[cfg(target_arch = "wasm32")] let spawner = { use futures::{future::LocalFutureObj, task::SpawnError}; use winit::platform::web::WindowExtWebSys; struct WebSpawner {} impl LocalSpawn for WebSpawner { fn spawn_local_obj( &self, future: LocalFutureObj<'static, ()>, ) -> Result<(), SpawnError> { Ok(wasm_bindgen_futures::spawn_local(future)) } } std::panic::set_hook(Box::new(console_error_panic_hook::hook)); // On wasm, append the canvas to the document body web_sys::window() .and_then(|win| win.document()) .and_then(|doc| doc.body()) .and_then(|body| { body.append_child(&web_sys::Element::from(window.canvas())) .ok() }) .expect("couldn't append canvas to document body"); WebSpawner {} };*/ log::info!("Done doing the loading part..."); let mut sc_desc = Arc::new(wgpu::SwapChainDescriptor { // Allows a texture to be a output attachment of a renderpass. usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, format: if cfg!(target_arch = "wasm32") { wgpu::TextureFormat::Bgra8Unorm } else { wgpu::TextureFormat::Bgra8UnormSrgb }, width: size.width, height: size.height, // The presentation engine waits for the next vertical blanking period to update present_mode: wgpu::PresentMode::Mailbox, }); let mut swap_chain = device.create_swap_chain(&surface, &sc_desc); let entity_uniform_size = mem::size_of::() as wgpu::BufferAddress; // This seems way way way way easier than what I was doing in tracer // Though the attr thing is still a macro. Which would cause issues if // I wanted to get tricky with the 0,1 types let vertex_size = mem::size_of::(); let vertex_attr = wgpu::vertex_attr_array![0 => Float4, 1 => Float4]; let vb_desc = wgpu::VertexBufferDescriptor { stride: vertex_size as wgpu::BufferAddress, step_mode: wgpu::InputStepMode::Vertex, attributes: &vertex_attr, }; // This is also in the runtime which really shouldn't have this let entity_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("Entity Bind Group Layout"), entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, count: None, ty: wgpu::BindingType::UniformBuffer { dynamic: false, min_binding_size: wgpu::BufferSize::new( mem::size_of::() as _ ), }, }], }); /* There appear to be two passes required for shadows, the shadow pass, and the forward pass Need to open this up in renderdoc and see what it's actually doing */ let shadow_pass = { let uniform_size = mem::size_of::() as wgpu::BufferAddress; // I believe this is just making a_Pos or u_ViewProj available in the vert shader let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("Shadow pass bind group layout"), entries: &[wgpu::BindGroupLayoutEntry { binding: 0, // global visibility: wgpu::ShaderStage::VERTEX, ty: wgpu::BindingType::UniformBuffer { dynamic: false, min_binding_size: wgpu::BufferSize::new(uniform_size), }, count: None, }], }); // Pipeline is similar between passes, but with a different label let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("shadow pass pipeline layout"), bind_group_layouts: &[&bind_group_layout, &entity_bind_group_layout], push_constant_ranges: &[], }); // Holds the shadow uniforms, which is just a 4 vec of quaternians let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { label: Some("shadow pass shadow uniform buffer"), size: uniform_size, usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, mapped_at_creation: false, }); // Create bind group let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &bind_group_layout, entries: &[wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)), }], label: Some("Shadow uniform bind group"), }); // Create the render pipeline let vs_module = device.create_shader_module(wgpu::include_spirv!("../resources/bake.vert.spv")); let fs_module = device.create_shader_module(wgpu::include_spirv!("../resources/bake.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("shadow"), layout: Some(&pipeline_layout), vertex_stage: wgpu::ProgrammableStageDescriptor { module: &vs_module, entry_point: "main", }, fragment_stage: Some(wgpu::ProgrammableStageDescriptor { module: &fs_module, entry_point: "main", }), rasterization_state: Some(wgpu::RasterizationStateDescriptor { front_face: wgpu::FrontFace::Ccw, cull_mode: wgpu::CullMode::Back, depth_bias: 2, // corresponds to bilinear filtering depth_bias_slope_scale: 2.0, depth_bias_clamp: 0.0, clamp_depth: device.features().contains(wgpu::Features::DEPTH_CLAMPING), }), primitive_topology: wgpu::PrimitiveTopology::TriangleList, color_states: &[], depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { format: Self::SHADOW_FORMAT, depth_write_enabled: true, depth_compare: wgpu::CompareFunction::LessEqual, stencil: wgpu::StencilStateDescriptor::default(), }), vertex_state: wgpu::VertexStateDescriptor { index_format: wgpu::IndexFormat::Uint32, vertex_buffers: &[vb_desc.clone()], }, sample_count: 1, sample_mask: !0, alpha_to_coverage_enabled: false, }); Pass { pipeline, bind_group, uniform_buf, } }; // Pre init the light uniform, with slots enough for MAX_LIGHTS let light_uniform_size = (Self::MAX_LIGHTS * mem::size_of::()) as wgpu::BufferAddress; let light_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { label: Some("Light uniform buffer"), size: light_uniform_size, usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::COPY_DST, mapped_at_creation: false, }); let shadow_texture = device.create_texture(&wgpu::TextureDescriptor { size: Self::SHADOW_SIZE, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::SHADOW_FORMAT, usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, label: Some("Shadow texture"), }); let mut shadow_target_views = (0..2) .map(|i| { Arc::new(shadow_texture.create_view(&wgpu::TextureViewDescriptor { label: Some("shadow"), format: None, dimension: Some(wgpu::TextureViewDimension::D2), aspect: wgpu::TextureAspect::All, base_mip_level: 0, level_count: None, base_array_layer: i as u32, array_layer_count: NonZeroU32::new(1), })) }) .collect::>(); let forward_pass = { // Create pipeline layout let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[ wgpu::BindGroupLayoutEntry { binding: 0, // global visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::UniformBuffer { dynamic: false, min_binding_size: wgpu::BufferSize::new(mem::size_of::< ForwardUniforms, >( ) as _), }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 1, // lights visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::UniformBuffer { dynamic: false, min_binding_size: wgpu::BufferSize::new(light_uniform_size), }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 2, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::SampledTexture { multisampled: false, component_type: wgpu::TextureComponentType::Float, dimension: wgpu::TextureViewDimension::D2Array, }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 3, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler { comparison: true }, count: None, }, ], label: Some("Forward pass bind group layout"), }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("main"), bind_group_layouts: &[&bind_group_layout, &entity_bind_group_layout], push_constant_ranges: &[], }); let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); // I need to know the number of lights... let forward_uniforms = ForwardUniforms { proj: *mx_total.as_ref(), //num_lights: [lights.len() as u32, 0, 0, 0], num_lights: [2 as u32, 0, 0, 0], }; let uniform_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Forward pass binding 0 uniform buffer"), contents: bytemuck::bytes_of(&forward_uniforms), usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, }); let shadow_sampler = device.create_sampler(&wgpu::SamplerDescriptor { label: Some("shadow"), address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge, mag_filter: wgpu::FilterMode::Linear, min_filter: wgpu::FilterMode::Linear, mipmap_filter: wgpu::FilterMode::Nearest, compare: Some(wgpu::CompareFunction::LessEqual), ..Default::default() }); let shadow_view = shadow_texture.create_view(&wgpu::TextureViewDescriptor::default()); // Create bind group let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &bind_group_layout, entries: &[ wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)), }, wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::Buffer(light_uniform_buf.slice(..)), }, wgpu::BindGroupEntry { binding: 2, resource: wgpu::BindingResource::TextureView(&shadow_view), }, wgpu::BindGroupEntry { binding: 3, resource: wgpu::BindingResource::Sampler(&shadow_sampler), }, ], label: Some("Forward pass bind group"), }); // Create the render pipeline let vs_module = device.create_shader_module(wgpu::include_spirv!("../resources/forward.vert.spv")); let fs_module = device.create_shader_module(wgpu::include_spirv!("../resources/forward.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("main"), layout: Some(&pipeline_layout), vertex_stage: wgpu::ProgrammableStageDescriptor { module: &vs_module, entry_point: "main", }, fragment_stage: Some(wgpu::ProgrammableStageDescriptor { module: &fs_module, entry_point: "main", }), rasterization_state: Some(wgpu::RasterizationStateDescriptor { front_face: wgpu::FrontFace::Ccw, cull_mode: wgpu::CullMode::Back, ..Default::default() }), primitive_topology: wgpu::PrimitiveTopology::TriangleList, color_states: &[sc_desc.format.into()], depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { format: Self::DEPTH_FORMAT, depth_write_enabled: true, depth_compare: wgpu::CompareFunction::Less, stencil: wgpu::StencilStateDescriptor::default(), }), vertex_state: wgpu::VertexStateDescriptor { index_format: wgpu::IndexFormat::Uint32, vertex_buffers: &[vb_desc], }, sample_count: 1, sample_mask: !0, alpha_to_coverage_enabled: false, }); Pass { pipeline, bind_group, uniform_buf, } }; let depth_texture = device.create_texture(&wgpu::TextureDescriptor { size: wgpu::Extent3d { width: sc_desc.width, height: sc_desc.height, depth: 1, }, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, label: Some("Depth Texture"), }); Renderer { window, swapchain: swap_chain, queue: queue, size, device: device, lights_are_dirty: true, shadow_pass, forward_pass, forward_depth: depth_texture.create_view(&wgpu::TextureViewDescriptor::default()), entity_bind_group_layout: entity_bind_group_layout, shadow_target_views: shadow_target_views, light_uniform_buf, swapchain_description: sc_desc, surface, instance: Arc::new(instance), views_given: 0, } } pub(crate) fn required_features() -> wgpu::Features { wgpu::Features::empty() } pub fn optional_features() -> wgpu::Features { wgpu::Features::DEPTH_CLAMPING } pub fn resize(&mut self, width: u32, height: u32) { // update view-projection matrix let mx_total = Self::generate_matrix(width as f32 / height as f32); let mx_ref: &[f32; 16] = mx_total.as_ref(); self.queue.write_buffer( &self.forward_pass.uniform_buf, 0, bytemuck::cast_slice(mx_ref), ); let depth_texture = self.device.create_texture(&wgpu::TextureDescriptor { size: wgpu::Extent3d { width: width, height: height, depth: 1, }, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, label: Some("Depth Texture"), }); self.forward_depth = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); } }