diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:23 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:23 +0100 |
commit | 47a0c0317cc774c19b78582bec9b5b09d56f569a (patch) | |
tree | d03471ea4e084ace9b95a2c5b7febb780b45bb63 /stockton-render/src/draw/draw_passes | |
parent | fb996488aa651cb2e7f46abc083c4318b47e77cd (diff) |
feat(render): draw passes
Diffstat (limited to 'stockton-render/src/draw/draw_passes')
-rw-r--r-- | stockton-render/src/draw/draw_passes/cons.rs | 45 | ||||
-rw-r--r-- | stockton-render/src/draw/draw_passes/level.rs | 812 | ||||
-rw-r--r-- | stockton-render/src/draw/draw_passes/mod.rs | 27 |
3 files changed, 448 insertions, 436 deletions
diff --git a/stockton-render/src/draw/draw_passes/cons.rs b/stockton-render/src/draw/draw_passes/cons.rs index 76e2f32..8f912ec 100644 --- a/stockton-render/src/draw/draw_passes/cons.rs +++ b/stockton-render/src/draw/draw_passes/cons.rs @@ -1,8 +1,10 @@ //! Code for using multiple draw passes in place of just one //! Note that this can be extended to an arbitrary amount of draw passes. +use std::sync::{Arc, RwLock}; + use super::DrawPass; -use crate::{draw::queue_negotiator::QueueNegotiator, types::*}; +use crate::types::*; use stockton_types::Session; use anyhow::Result; @@ -14,23 +16,21 @@ pub struct ConsDrawPass<A: DrawPass, B: DrawPass> { } impl<A: DrawPass, B: DrawPass> DrawPass for ConsDrawPass<A, B> { - fn queue_draw(&self, session: &Session, cmd_buffer: &mut CommandBufferT) -> Result<()> { - self.a.queue_draw(&session, cmd_buffer)?; - self.b.queue_draw(&session, cmd_buffer)?; + fn queue_draw( + &mut self, + session: &Session, + img_view: &ImageViewT, + cmd_buffer: &mut CommandBufferT, + ) -> Result<()> { + self.a.queue_draw(session, img_view, cmd_buffer)?; + self.b.queue_draw(session, img_view, cmd_buffer)?; Ok(()) } - fn find_aux_queues<'a>( - adapter: &'a Adapter, - queue_negotiator: &mut QueueNegotiator, - ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>> { - let mut vec = Vec::new(); - - vec.extend(A::find_aux_queues(adapter, queue_negotiator)?); - vec.extend(B::find_aux_queues(adapter, queue_negotiator)?); - - Ok(vec) + fn deactivate(self, device: &mut Arc<RwLock<DeviceT>>) -> Result<()> { + self.a.deactivate(device)?; + self.b.deactivate(device) } } @@ -38,15 +38,16 @@ impl<A: DrawPass, B: DrawPass> DrawPass for ConsDrawPass<A, B> { pub struct NilDrawPass; impl DrawPass for NilDrawPass { - - fn queue_draw(&self, _input: &Session, _cmd_buffer: &mut CommandBufferT) -> Result<()> { + fn queue_draw( + &mut self, + _input: &Session, + _img_view: &ImageViewT, + _cmd_buffer: &mut CommandBufferT, + ) -> Result<()> { Ok(()) } - fn find_aux_queues<'a>( - _adapter: &'a Adapter, - _queue_negotiator: &mut QueueNegotiator, - ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>> { - Ok(vec![]) + fn deactivate(self, _device: &mut Arc<RwLock<DeviceT>>) -> Result<()> { + Ok(()) } -}
\ No newline at end of file +} diff --git a/stockton-render/src/draw/draw_passes/level.rs b/stockton-render/src/draw/draw_passes/level.rs index b968a1a..3a4e748 100644 --- a/stockton-render/src/draw/draw_passes/level.rs +++ b/stockton-render/src/draw/draw_passes/level.rs @@ -2,18 +2,57 @@ use super::{DrawPass, IntoDrawPass}; use crate::{ - draw::{queue_negotiator::QueueNegotiator, target::SwapchainProperties, texture::TextureRepo}, - error::EnvironmentError, + draw::{ + buffers::{ + draw_buffers::{DrawBuffers, INITIAL_INDEX_SIZE, INITIAL_VERT_SIZE}, + DedicatedLoadedImage, ModifiableBuffer, + }, + builders::{ + pipeline::{ + CompletePipeline, PipelineSpecBuilder, VertexBufferSpec, + VertexPrimitiveAssemblerSpec, + }, + renderpass::RenderpassSpec, + shader::ShaderDesc, + }, + queue_negotiator::QueueNegotiator, + target::SwapchainProperties, + texture::{resolver::FsResolver, TexLoadQueue, TextureLoadConfig, TextureRepo}, + }, + error::{EnvironmentError, LevelError, LockPoisoned}, types::*, }; -use stockton_levels::features::MinRenderFeatures; -use stockton_types::*; +use hal::{ + buffer::SubRange, + command::{ClearColor, ClearDepthStencil, ClearValue, RenderAttachmentInfo, SubpassContents}, + format::{Aspects, Format}, + image::{ + Filter, FramebufferAttachment, Layout, SubresourceRange, Usage, ViewCapabilities, WrapMode, + }, + pass::{Attachment, AttachmentLoadOp, AttachmentOps, AttachmentStoreOp}, + pso::{ + BlendDesc, BlendOp, BlendState, ColorBlendDesc, ColorMask, Comparison, DepthStencilDesc, + DepthTest, Face, Factor, FrontFace, InputAssemblerDesc, LogicOp, PolygonMode, Primitive, + Rasterizer, ShaderStageFlags, State, VertexInputRate, + }, +}; +use legion::{Entity, IntoQuery}; +use shaderc::ShaderKind; +use stockton_levels::{ + features::MinRenderFeatures, + parts::{data::Geometry, IsFace}, +}; +use stockton_types::{ + components::{CameraSettings, CameraVPMatrix, Transform}, + *, +}; use std::{ array::IntoIter, + convert::TryInto, iter::{empty, once}, marker::PhantomData, - mem::{size_of, ManuallyDrop}, + path::Path, sync::{Arc, RwLock}, }; @@ -24,435 +63,398 @@ use anyhow::{Context, Result}; struct UvPoint(pub Vector3, pub i32, pub Vector2); /// Draw a level -pub struct LevelDrawPass<M: MinRenderFeatures> { +pub struct LevelDrawPass<'a, M> { pipeline: CompletePipeline, repo: TextureRepo, + active_camera: Entity, + draw_buffers: DrawBuffers<'a, UvPoint>, + + framebuffers: Vec<FramebufferT>, + depth_buffers: Vec<DedicatedLoadedImage>, + next_resources: usize, + _d: PhantomData<M>, } -impl<M: MinRenderFeatures> DrawPass for LevelDrawPass<M> { +impl<'a, M> DrawPass for LevelDrawPass<'a, M> +where + M: for<'b> MinRenderFeatures<'b> + 'static, +{ fn queue_draw( - &self, - _input: &Session, - _cmd_buffer: &mut crate::types::CommandBufferT, + &mut self, + session: &Session, + img_view: &ImageViewT, + cmd_buffer: &mut crate::types::CommandBufferT, ) -> anyhow::Result<()> { - todo!() - // // Get visible faces - // // let faces = get_visible_faces( - // // pos, - // // &*self - // // .context - // // .map - // // .read() - // // .map_err(|_| LockPoisoned::Map) - // // .context("Error getting read lock on map")?, - // // ); - // let faces: Vec<u32> = { - // let map = &*self - // .context - // .map - // .read() - // .map_err(|_| LockPoisoned::Map) - // .context("Error getting read lock on map")?; - - // map.iter_faces().map(|x| x.index(map)).collect() - // }; - - // // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once. - // let mut current_chunk = file - // .get_face(0) - // .ok_or(LevelError::BadReference)? - // .texture_idx(file) as usize - // / 8; - // let mut chunk_start = 0; - - // let mut curr_vert_idx: usize = 0; - // let mut curr_idx_idx: usize = 0; - - // for face in faces.iter().map(|idx| file.get_face(*idx)) { - // if let Some(face) = face { - // if current_chunk != face.texture_idx(file) as usize / 8 { - // // Last index was last of group, so draw it all if textures are loaded. - // draw_or_queue( - // current_chunk, - // self.tex_repo, - // cmd_buffer, - // self.pipeline.pipeline_layout, - // chunk_start as u32, - // curr_idx_idx as u32, - // )?; - - // // Next group of same-chunked faces starts here. - // chunk_start = curr_idx_idx; - // current_chunk = face.texture_idx(file) as usize / 8; - // } - - // match face.geometry(file) { - // Geometry::Vertices(v1, v2, v3) => { - // for v in [v1, v2, v3] { - // let uvp = - // UvPoint(v.position, face.texture_idx(file).try_into()?, v.tex); - - // draw_buffers.vertex_buffer[curr_vert_idx] = uvp; - // curr_vert_idx += 1; - // } - // draw_buffers.index_buffer[curr_idx_idx] = ( - // curr_vert_idx as u16 - 2, - // curr_vert_idx as u16 - 1, - // curr_vert_idx as u16, - // ); - // curr_idx_idx += 1; - // } - // } - - // if curr_vert_idx >= INITIAL_VERT_SIZE.try_into()? - // || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into()? - // { - // println!("out of vertex buffer space!"); - // break; - // } - // } else { - // anyhow::bail!(LevelError::BadReference); - // } - // } - - // // Draw the final group of chunks - // draw_or_queue( - // current_chunk, - // self.tex_repo, - // cmd_buffer, - // self.pipeline.pipeline_layout, - // chunk_start as u32, - // curr_idx_idx as u32, - // )?; - - // Ok(()) - } - - fn find_aux_queues<'a>( - _adapter: &'a Adapter, - _queue_negotiator: &mut QueueNegotiator, - ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>> { - todo!() - // queue_negotiator.find(TexLoadQueue) - } -} - -impl<M: MinRenderFeatures> IntoDrawPass<LevelDrawPass<M>> for () { - fn init( - self, - _device_lock: Arc<RwLock<DeviceT>>, - _queue_negotiator: &mut QueueNegotiator, - _swapchain_properties: &SwapchainProperties, - ) -> Result<LevelDrawPass<M>> { - todo!() - // let repo = TextureRepo::new( - // device_lock.clone(), - // queue_negotiator - // .family() - // .ok_or(EnvironmentError::NoQueues)?, - // ); - // let pipeline = { - // let device = device_lock.write().or(Err(LockPoisoned::Device))?; - // CompletePipeline::new( - // device, - // swapchain_properties.extent, - // swapchain_properties, - // std::iter::empty(), - // )? - // }; - // Ok(LevelDrawPass { - // pipeline, - // repo, - // _d: PhantomData, - // }) - } -} - -/// Entry point name for shaders -const ENTRY_NAME: &str = "main"; - -/// Source for vertex shader. TODO -const VERTEX_SOURCE: &str = include_str!("../data/stockton.vert"); + // We might have loaded more textures + self.repo.process_responses(); + + // Make sure we update the vertex buffers after they're written to, but before they're read from. + self.draw_buffers + .vertex_buffer + .record_commit_cmds(cmd_buffer)?; + self.draw_buffers + .index_buffer + .record_commit_cmds(cmd_buffer)?; + + // Get level & camera + let mut query = <(&Transform, &CameraSettings, &CameraVPMatrix)>::query(); + let (camera_transform, camera_settings, camera_vp) = query + .get(&session.world, self.active_camera) + .context("Couldn't find camera components")?; + let map_lock: Arc<RwLock<M>> = session.resources.get::<Arc<RwLock<M>>>().unwrap().clone(); + let map = map_lock.read().map_err(|_| LockPoisoned::Map)?; + + // Get framebuffer and depth buffer + let fb = &self.framebuffers[self.next_resources]; + let db = &self.depth_buffers[self.next_resources]; + self.next_resources = (self.next_resources + 1) % self.framebuffers.len(); -/// Source for fragment shader. TODO -const FRAGMENT_SOURCE: &str = include_str!("../data/stockton.frag"); - -/// A complete graphics pipeline and associated resources -pub struct CompletePipeline { - /// Our main render pass - pub(crate) renderpass: ManuallyDrop<RenderPassT>, - - /// The layout of our main graphics pipeline - pub(crate) pipeline_layout: ManuallyDrop<PipelineLayoutT>, - - /// Our main graphics pipeline - pub(crate) pipeline: ManuallyDrop<GraphicsPipelineT>, - - /// The vertex shader module - pub(crate) vs_module: ManuallyDrop<ShaderModuleT>, + unsafe { + cmd_buffer.begin_render_pass( + &self.pipeline.renderpass, + fb, + self.pipeline.render_area, + vec![ + RenderAttachmentInfo { + image_view: img_view, + clear_value: ClearValue { + color: ClearColor { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }, + }, + RenderAttachmentInfo { + image_view: &*db.image_view, + clear_value: ClearValue { + depth_stencil: ClearDepthStencil { + depth: 1.0, + stencil: 0, + }, + }, + }, + ] + .into_iter(), + SubpassContents::Inline, + ); + cmd_buffer.bind_graphics_pipeline(&self.pipeline.pipeline); + + // VP Matrix + let vp = &*(camera_vp.vp_matrix.data.as_slice() as *const [f32] as *const [u32]); + + cmd_buffer.push_graphics_constants( + &self.pipeline.pipeline_layout, + ShaderStageFlags::VERTEX, + 0, + vp, + ); + + // Bind buffers + cmd_buffer.bind_vertex_buffers( + 0, + once(( + self.draw_buffers.vertex_buffer.get_buffer(), + SubRange { + offset: 0, + size: None, + }, + )), + ); + cmd_buffer.bind_index_buffer( + self.draw_buffers.index_buffer.get_buffer(), + SubRange { + offset: 0, + size: None, + }, + hal::IndexType::U16, + ); + } - /// The fragment shader module - pub(crate) fs_module: ManuallyDrop<ShaderModuleT>, -} + // Get visible faces + let mut faces = map.get_visible(camera_transform, camera_settings); + + // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once. + let face = faces.next(); + if let Some(face) = face { + let mut face = map.get_face(face).ok_or(LevelError::BadReference)?; + let mut current_chunk = face.texture_idx(&map) as usize / 8; + let mut chunk_start = 0; + + let mut curr_vert_idx: usize = 0; + let mut curr_idx_idx: usize = 0; + loop { + if current_chunk != face.texture_idx(&map) as usize / 8 { + // Last index was last of group, so draw it all if textures are loaded. + draw_or_queue( + current_chunk, + &mut self.repo, + cmd_buffer, + &*self.pipeline.pipeline_layout, + chunk_start as u32, + curr_idx_idx as u32, + )?; + + // Next group of same-chunked faces starts here. + chunk_start = curr_idx_idx; + current_chunk = face.texture_idx(&map) as usize / 8; + } + + match face.geometry(&map) { + Geometry::Vertices(v1, v2, v3) => { + for v in [v1, v2, v3] { + let uvp = + UvPoint(v.position, face.texture_idx(&map).try_into()?, v.tex); + + self.draw_buffers.vertex_buffer[curr_vert_idx] = uvp; + curr_vert_idx += 1; + } + self.draw_buffers.index_buffer[curr_idx_idx] = ( + curr_vert_idx as u16 - 3, + curr_vert_idx as u16 - 2, + curr_vert_idx as u16 - 1, + ); + curr_idx_idx += 1; + } + } + + if curr_vert_idx >= INITIAL_VERT_SIZE.try_into()? + || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into()? + { + println!("out of vertex buffer space!"); + break; + } + + match faces.next() { + Some(x) => face = map.get_face(x).ok_or(LevelError::BadReference)?, + None => break, + }; + } -impl CompletePipeline { - pub fn new<'a, T: Iterator<Item = &'a DescriptorSetLayoutT> + std::fmt::Debug>( - device: &mut DeviceT, - extent: hal::image::Extent, - swapchain_properties: &SwapchainProperties, - set_layouts: T, - ) -> Result<Self> { - use hal::format::Format; - use hal::pso::*; - - // Renderpass - let renderpass = { - use hal::{image::Layout, pass::*}; - - let img_attachment = Attachment { - format: Some(swapchain_properties.format), - samples: 1, - ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::Store), - stencil_ops: AttachmentOps::new( - AttachmentLoadOp::Clear, - AttachmentStoreOp::DontCare, - ), - layouts: Layout::Undefined..Layout::ColorAttachmentOptimal, - }; + // Draw the final group of chunks + draw_or_queue( + current_chunk, + &mut self.repo, + cmd_buffer, + &*self.pipeline.pipeline_layout, + chunk_start as u32, + curr_idx_idx as u32, + )?; + } - let depth_attachment = Attachment { - format: Some(swapchain_properties.depth_format), - samples: 1, - ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::DontCare), - stencil_ops: AttachmentOps::new( - AttachmentLoadOp::DontCare, - AttachmentStoreOp::DontCare, - ), - layouts: Layout::Undefined..Layout::DepthStencilAttachmentOptimal, - }; + unsafe { + cmd_buffer.end_render_pass(); + } - let subpass = SubpassDesc { - colors: &[(0, Layout::ColorAttachmentOptimal)], - depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)), - inputs: &[], - resolves: &[], - preserves: &[], - }; + Ok(()) + } - unsafe { - device.create_render_pass( - IntoIter::new([img_attachment, depth_attachment]), - once(subpass), - empty(), - ) + fn deactivate(self, device_lock: &mut Arc<RwLock<DeviceT>>) -> Result<()> { + unsafe { + let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?; + self.pipeline.deactivate(&mut device); + self.draw_buffers.deactivate(&mut device); + for fb in self.framebuffers.into_iter() { + device.destroy_framebuffer(fb); } - .context("Error creating render pass")? - }; - - // Subpass - let subpass = hal::pass::Subpass { - index: 0, - main_pass: &renderpass, - }; - - // Shader modules - let (vs_module, fs_module) = { - let mut compiler = shaderc::Compiler::new().ok_or(EnvironmentError::NoShaderC)?; - - let vertex_compile_artifact = compiler - .compile_into_spirv( - VERTEX_SOURCE, - shaderc::ShaderKind::Vertex, - "vertex.vert", - ENTRY_NAME, - None, - ) - .context("Error compiling vertex shader")?; - - let fragment_compile_artifact = compiler - .compile_into_spirv( - FRAGMENT_SOURCE, - shaderc::ShaderKind::Fragment, - "fragment.frag", - ENTRY_NAME, - None, - ) - .context("Error compiling fragment shader")?; - - // Make into shader module - unsafe { - ( - device - .create_shader_module(vertex_compile_artifact.as_binary()) - .context("Error creating vertex shader module")?, - device - .create_shader_module(fragment_compile_artifact.as_binary()) - .context("Error creating fragment shader module")?, - ) + for db in self.depth_buffers.into_iter() { + db.deactivate(&mut device); } - }; - - // Shader entry points (ShaderStage) - let (vs_entry, fs_entry) = ( - EntryPoint::<back::Backend> { - entry: ENTRY_NAME, - module: &vs_module, - specialization: Specialization::default(), - }, - EntryPoint::<back::Backend> { - entry: ENTRY_NAME, - module: &fs_module, - specialization: Specialization::default(), - }, - ); - - // Rasterizer - let rasterizer = Rasterizer { - polygon_mode: PolygonMode::Fill, - cull_face: Face::BACK, - front_face: FrontFace::CounterClockwise, - depth_clamping: false, - depth_bias: None, - conservative: true, - line_width: State::Static(1.0), - }; - - // Depth stencil - let depth_stencil = DepthStencilDesc { - depth: Some(DepthTest { - fun: Comparison::Less, - write: true, - }), - depth_bounds: false, - stencil: None, - }; - - // Pipeline layout - let layout = unsafe { - device.create_pipeline_layout( - set_layouts.into_iter(), - // vp matrix, 4x4 f32 - IntoIter::new([(ShaderStageFlags::VERTEX, 0..64)]), - ) } - .context("Error creating pipeline layout")?; - - // Colour blending - let blender = { - let blend_state = BlendState { - color: BlendOp::Add { - src: Factor::One, - dst: Factor::Zero, - }, - alpha: BlendOp::Add { - src: Factor::One, - dst: Factor::Zero, - }, - }; + self.repo.deactivate(device_lock); + + Ok(()) + } +} - BlendDesc { +impl<'a, M> IntoDrawPass<LevelDrawPass<'a, M>> for Entity +where + M: for<'b> MinRenderFeatures<'b> + 'static, +{ + fn init( + self, + session: &Session, + adapter: &Adapter, + device_lock: Arc<RwLock<DeviceT>>, + queue_negotiator: &mut QueueNegotiator, + swapchain_properties: &SwapchainProperties, + ) -> Result<LevelDrawPass<'a, M>> { + let spec = PipelineSpecBuilder::default() + .rasterizer(Rasterizer { + polygon_mode: PolygonMode::Fill, + cull_face: Face::BACK, + front_face: FrontFace::CounterClockwise, + depth_clamping: false, + depth_bias: None, + conservative: true, + line_width: State::Static(1.0), + }) + .depth_stencil(DepthStencilDesc { + depth: Some(DepthTest { + fun: Comparison::Less, + write: true, + }), + depth_bounds: false, + stencil: None, + }) + .blender(BlendDesc { logic_op: Some(LogicOp::Copy), targets: vec![ColorBlendDesc { mask: ColorMask::ALL, - blend: Some(blend_state), + blend: Some(BlendState { + color: BlendOp::Add { + src: Factor::One, + dst: Factor::Zero, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::Zero, + }, + }), + }], + }) + .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers( + InputAssemblerDesc::new(Primitive::TriangleList), + vec![VertexBufferSpec { + attributes: vec![Format::Rgb32Sfloat, Format::R32Sint, Format::Rg32Sfloat], + rate: VertexInputRate::Vertex, + }], + )) + .shader_vertex(ShaderDesc { + source: include_str!("../data/stockton.vert").to_string(), + entry: "main".to_string(), + kind: ShaderKind::Vertex, + }) + .shader_fragment(ShaderDesc { + source: include_str!("../data/stockton.frag").to_string(), + entry: "main".to_string(), + kind: ShaderKind::Fragment, + }) + .push_constants(vec![(ShaderStageFlags::VERTEX, 0..64)]) + .renderpass(RenderpassSpec { + colors: vec![Attachment { + format: Some(swapchain_properties.format), + samples: 1, + ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::Store), + stencil_ops: AttachmentOps::new( + AttachmentLoadOp::Clear, + AttachmentStoreOp::DontCare, + ), + layouts: Layout::ColorAttachmentOptimal..Layout::ColorAttachmentOptimal, }], + depth: Some(Attachment { + format: Some(swapchain_properties.depth_format), + samples: 1, + ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::DontCare), + stencil_ops: AttachmentOps::new( + AttachmentLoadOp::DontCare, + AttachmentStoreOp::DontCare, + ), + layouts: Layout::Undefined..Layout::DepthStencilAttachmentOptimal, + }), + inputs: vec![], + resolves: vec![], + preserves: vec![], + }) + .build() + .context("Error building pipeline")?; + + let map_lock: Arc<RwLock<M>> = session.resources.get::<Arc<RwLock<M>>>().unwrap().clone(); + let repo = TextureRepo::new( + device_lock.clone(), + queue_negotiator + .family::<TexLoadQueue>() + .ok_or(EnvironmentError::NoSuitableFamilies) + .context("Error finding texture queue")?, + queue_negotiator + .get_queue::<TexLoadQueue>() + .ok_or(EnvironmentError::NoQueues) + .context("Error finding texture queue")?, + adapter, + TextureLoadConfig { + resolver: FsResolver::new(Path::new("textures"), map_lock), + filter: Filter::Linear, + wrap_mode: WrapMode::Tile, + }, + ) + .context("Error creating texture repo")?; + + let (draw_buffers, pipeline, framebuffers, depth_buffers) = { + let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?; + let draw_buffers = + DrawBuffers::new(&mut device, adapter).context("Error creating draw buffers")?; + let pipeline = spec + .build( + &mut device, + swapchain_properties.extent, + swapchain_properties, + once(&*repo.get_ds_layout()?), + ) + .context("Error building pipeline")?; + + let mut framebuffers = Vec::with_capacity(swapchain_properties.image_count as usize); + let mut depth_buffers = Vec::with_capacity(swapchain_properties.image_count as usize); + let fat = FramebufferAttachment { + usage: Usage::COLOR_ATTACHMENT, + format: swapchain_properties.format, + view_caps: ViewCapabilities::empty(), + }; + let dat = FramebufferAttachment { + usage: Usage::DEPTH_STENCIL_ATTACHMENT, + format: swapchain_properties.depth_format, + view_caps: ViewCapabilities::empty(), + }; + for _i in 0..swapchain_properties.image_count { + unsafe { + framebuffers.push(device.create_framebuffer( + &pipeline.renderpass, + IntoIter::new([fat.clone(), dat.clone()]), + swapchain_properties.extent, + )?); + depth_buffers.push( + DedicatedLoadedImage::new( + &mut device, + adapter, + swapchain_properties.depth_format, + Usage::DEPTH_STENCIL_ATTACHMENT, + SubresourceRange { + aspects: Aspects::DEPTH, + level_start: 0, + level_count: Some(1), + layer_start: 0, + layer_count: Some(1), + }, + swapchain_properties.extent.width as usize, + swapchain_properties.extent.height as usize, + ) + .context("Error creating depth buffer")?, + ) + } } - }; - - // Baked states - let baked_states = BakedStates { - viewport: Some(Viewport { - rect: extent.rect(), - depth: (0.0..1.0), - }), - scissor: Some(extent.rect()), - blend_constants: None, - depth_bounds: None, - }; - - // Primitive assembler - let primitive_assembler = PrimitiveAssemblerDesc::Vertex { - buffers: &[VertexBufferDesc { - binding: 0, - stride: (size_of::<f32>() * 6) as u32, - rate: VertexInputRate::Vertex, - }], - attributes: &[ - AttributeDesc { - location: 0, - binding: 0, - element: Element { - format: Format::Rgb32Sfloat, - offset: 0, - }, - }, - AttributeDesc { - location: 1, - binding: 0, - element: Element { - format: Format::R32Sint, - offset: (size_of::<f32>() * 3) as u32, - }, - }, - AttributeDesc { - location: 2, - binding: 0, - element: Element { - format: Format::Rg32Sfloat, - offset: (size_of::<f32>() * 4) as u32, - }, - }, - ], - input_assembler: InputAssemblerDesc::new(Primitive::TriangleList), - vertex: vs_entry, - tessellation: None, - geometry: None, - }; - // Pipeline description - let pipeline_desc = GraphicsPipelineDesc { - label: Some("3D"), - rasterizer, - fragment: Some(fs_entry), - blender, - depth_stencil, - multisampling: None, - baked_states, - layout: &layout, - subpass, - flags: PipelineCreationFlags::empty(), - parent: BasePipeline::None, - primitive_assembler, + (draw_buffers, pipeline, framebuffers, depth_buffers) }; - // Pipeline - let pipeline = unsafe { device.create_graphics_pipeline(&pipeline_desc, None) } - .context("Error creating graphics pipeline")?; - - Ok(CompletePipeline { - renderpass: ManuallyDrop::new(renderpass), - pipeline_layout: ManuallyDrop::new(layout), - pipeline: ManuallyDrop::new(pipeline), - vs_module: ManuallyDrop::new(vs_module), - fs_module: ManuallyDrop::new(fs_module), + Ok(LevelDrawPass { + pipeline, + repo, + draw_buffers, + active_camera: self, + _d: PhantomData, + framebuffers, + depth_buffers, + next_resources: 0, }) } - /// Deactivate vulkan resources. Use before dropping - pub fn deactivate(self, device: &mut DeviceT) { - unsafe { - use core::ptr::read; - - device.destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass))); - - device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module))); - device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module))); + fn find_aux_queues<'c>( + adapter: &'c Adapter, + queue_negotiator: &mut QueueNegotiator, + ) -> Result<Vec<(&'c QueueFamilyT, Vec<f32>)>> { + queue_negotiator.find(adapter, &TexLoadQueue)?; - device.destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline))); - - device.destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout))); - } + Ok(vec![queue_negotiator + .family_spec::<TexLoadQueue>(&adapter.queue_families, 1) + .ok_or(EnvironmentError::NoSuitableFamilies)?]) } } diff --git a/stockton-render/src/draw/draw_passes/mod.rs b/stockton-render/src/draw/draw_passes/mod.rs index 566a64b..70f1786 100644 --- a/stockton-render/src/draw/draw_passes/mod.rs +++ b/stockton-render/src/draw/draw_passes/mod.rs @@ -10,22 +10,21 @@ use anyhow::Result; mod cons; mod level; -pub use level::LevelDrawPass; pub use cons::{ConsDrawPass, NilDrawPass}; +pub use level::LevelDrawPass; /// One of several 'passes' that draw on each frame. pub trait DrawPass { /// Queue any necessary draw commands to cmd_buffer /// This should assume the command buffer isn't in the middle of a renderpass, and should leave it as such. - fn queue_draw(&self, session: &Session, cmd_buffer: &mut CommandBufferT) -> Result<()>; + fn queue_draw( + &mut self, + session: &Session, + img_view: &ImageViewT, + cmd_buffer: &mut CommandBufferT, + ) -> Result<()>; - /// This function should ask the queue negotatior to find families for any auxilary operations this draw pass needs to perform - /// For example, .find(&TexLoadQueue) - /// It should return then call .family_spec for each queue type negotiated and return the results. - fn find_aux_queues<'a>( - adapter: &'a Adapter, - queue_negotiator: &mut QueueNegotiator, - ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>>; + fn deactivate(self, device: &mut Arc<RwLock<DeviceT>>) -> Result<()>; } /// A type that can be made into a specific draw pass type. @@ -33,8 +32,18 @@ pub trait DrawPass { pub trait IntoDrawPass<O: DrawPass> { fn init( self, + session: &Session, + adapter: &Adapter, device: Arc<RwLock<DeviceT>>, queue_negotiator: &mut QueueNegotiator, swapchain_properties: &SwapchainProperties, ) -> Result<O>; + + /// This function should ask the queue negotatior to find families for any auxilary operations this draw pass needs to perform + /// For example, .find(&TexLoadQueue) + /// It should return then call .family_spec for each queue type negotiated and return the results. + fn find_aux_queues<'a>( + adapter: &'a Adapter, + queue_negotiator: &mut QueueNegotiator, + ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>>; } |