diff options
Diffstat (limited to 'stockton-render/src/draw/context.rs')
-rw-r--r-- | stockton-render/src/draw/context.rs | 307 |
1 files changed, 61 insertions, 246 deletions
diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs index 4231a2e..2d3d92d 100644 --- a/stockton-render/src/draw/context.rs +++ b/stockton-render/src/draw/context.rs @@ -1,32 +1,22 @@ //! Deals with all the Vulkan/HAL details. -//! In the end, this takes in a depth-sorted list of faces and a map file and renders them. -//! You'll need something else to actually find/sort the faces though. +//! This relies on draw passes for the actual drawing logic. use std::{ - iter::once, mem::ManuallyDrop, + ptr::read, sync::{Arc, RwLock}, }; use anyhow::{Context, Result}; -use arrayvec::ArrayVec; use hal::pool::CommandPoolCreateFlags; use log::debug; use na::Mat4; use winit::window::Window; use super::{ - buffer::ModifiableBuffer, - draw_buffers::{DrawBuffers, UvPoint}, - pipeline::CompletePipeline, + draw_passes::{DrawPass, IntoDrawPass, LevelDrawPass}, queue_negotiator::{DrawQueue, QueueNegotiator}, - render::do_render, target::{SwapchainProperties, TargetChain}, - texture::{resolver::FsResolver, TexLoadQueue, TextureLoadConfig, TextureRepo}, - ui::{ - do_render as do_render_ui, ensure_textures as ensure_textures_ui, UiPipeline, UiPoint, - UiTextures, - }, }; use crate::{ error::{EnvironmentError, LockPoisoned}, @@ -38,7 +28,7 @@ use stockton_levels::prelude::*; /// Contains all the hal related stuff. /// In the end, this takes in a depth-sorted list of faces and a map file and renders them. // TODO: Settings for clear colour, buffer sizes, etc -pub struct RenderingContext<'a, M: 'static + MinBspFeatures<VulkanSystem>> { +pub struct RenderingContext<M: 'static + MinRenderFeatures, DP = LevelDrawPass<M>> { pub map: Arc<RwLock<M>>, // Parents for most of these things @@ -54,12 +44,6 @@ pub struct RenderingContext<'a, M: 'static + MinBspFeatures<VulkanSystem>> { /// Swapchain and stuff pub(crate) target_chain: ManuallyDrop<TargetChain>, - /// Graphics pipeline and associated objects - pipeline: ManuallyDrop<CompletePipeline>, - - /// 2D Graphics pipeline and associated objects - ui_pipeline: ManuallyDrop<UiPipeline>, - // Command pool and buffers /// The command pool used for our buffers cmd_pool: ManuallyDrop<CommandPoolT>, @@ -67,17 +51,8 @@ pub struct RenderingContext<'a, M: 'static + MinBspFeatures<VulkanSystem>> { /// The queue to use for drawing queue: Arc<RwLock<QueueT>>, - /// Main Texture repo - tex_repo: ManuallyDrop<TextureRepo<'a>>, - - /// UI Texture repo - ui_tex_repo: ManuallyDrop<TextureRepo<'a>>, - - /// Buffers used for drawing - draw_buffers: ManuallyDrop<DrawBuffers<'a, UvPoint>>, - - /// Buffers used for drawing the UI - ui_draw_buffers: ManuallyDrop<DrawBuffers<'a, UiPoint>>, + /// Deals with drawing logic, and holds any data required for drawing. + draw_pass: ManuallyDrop<DP>, /// View projection matrix pub(crate) vp_matrix: Mat4, @@ -85,9 +60,18 @@ pub struct RenderingContext<'a, M: 'static + MinBspFeatures<VulkanSystem>> { pub(crate) pixels_per_point: f32, } -impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { +impl<M: 'static + MinRenderFeatures, DP> RenderingContext<M, DP> +where + DP: DrawPass<Input = M>, +{ + // TODO: Arbitrary drawpass input /// Create a new RenderingContext for the given window. - pub fn new(window: &Window, ui: &mut UiState, map: M) -> Result<Self> { + pub fn new<ILDP: IntoDrawPass<DP>>( + window: &Window, + _ui: &mut UiState, + map: M, + idp: ILDP, + ) -> Result<Self> { let map = Arc::new(RwLock::new(map)); // Create surface let (instance, surface, mut adapters) = unsafe { @@ -104,46 +88,65 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { // TODO: Properly figure out which adapter to use let adapter = adapters.remove(0); + // Queue Negotiator + let mut queue_families_specs = Vec::new(); let (mut queue_negotiator, surface) = { let dq: DrawQueue = DrawQueue { surface }; - let qn = QueueNegotiator::find(&adapter, &[&dq, &TexLoadQueue]) - .context("Error creating draw queue negotiator")?; + let mut qn = QueueNegotiator::new(); + + // Draw Queue + qn.find(&adapter, &dq) + .context("Couldn't find draw queue family")?; + queue_families_specs.push( + qn.family_spec::<DrawQueue>(&adapter.queue_families, 1) + .context("Couldn't find draw queue family")?, + ); + + // Auxiliary queues for DP + queue_families_specs.extend( + DP::find_aux_queues(&adapter, &mut qn) + .context("Level pass couldn't populate queue negotiator")?, + ); (qn, dq.surface) }; // Device & Queue groups let (device_lock, mut queue_groups) = { - let (df, dqs) = queue_negotiator - .family_spec::<DrawQueue>(&adapter.queue_families, 1) - .ok_or(EnvironmentError::NoSuitableFamilies)?; - let (tf, tqs) = queue_negotiator - .family_spec::<TexLoadQueue>(&adapter.queue_families, 2) - .ok_or(EnvironmentError::NoSuitableFamilies)?; + // TODO: This sucks, but hal is restrictive on how we can pass this specific argument. + let queue_families_specs_real: Vec<_> = queue_families_specs + .iter() + .map(|(qf, ns)| (*qf, ns.as_slice())) + .collect(); let gpu = unsafe { adapter .physical_device - .open( - &[(df, dqs.as_slice()), (tf, tqs.as_slice())], - hal::Features::empty(), - ) + .open(queue_families_specs_real.as_slice(), hal::Features::empty()) .context("Error opening logical device")? }; (Arc::new(RwLock::new(gpu.device)), gpu.queue_groups) }; + // Figure out what our swapchain will look like + let swapchain_properties = SwapchainProperties::find_best(&adapter, &surface) + .context("Error getting properties for swapchain")?; + + // Draw pass + let dp = idp.init( + device_lock.clone(), + &mut queue_negotiator, + &swapchain_properties, + )?; + + // Lock device let mut device = device_lock .write() .map_err(|_| LockPoisoned::Device) .context("Error getting device lock")?; - // Figure out what our swapchain will look like - let swapchain_properties = SwapchainProperties::find_best(&adapter, &surface) - .context("Error getting properties for swapchain")?; - debug!("Detected swapchain properties: {:?}", swapchain_properties); // Command pool @@ -157,92 +160,18 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { } .context("Error creating draw command pool")?; - // Vertex and index buffers - let draw_buffers = - DrawBuffers::new(&mut device, &adapter).context("Error creating 3D draw buffers")?; - - // UI Vertex and index buffers - let ui_draw_buffers = - DrawBuffers::new(&mut device, &adapter).context("Error creating UI draw buffers")?; - - // We have to unlock device for creating texture repos - drop(device); - - // Texture repos - debug!("Creating 3D Texture Repo"); - let tex_repo = TextureRepo::new( - device_lock.clone(), - queue_negotiator - .family::<TexLoadQueue>() - .ok_or(EnvironmentError::NoQueues)?, - queue_negotiator - .get_queue::<TexLoadQueue>(&mut queue_groups) - .ok_or(EnvironmentError::NoQueues) - .context("Error getting 3D texture loader queue")?, - &adapter, - TextureLoadConfig { - resolver: FsResolver::new(std::path::Path::new("."), map.clone()), - filter: hal::image::Filter::Linear, - wrap_mode: hal::image::WrapMode::Tile, - }, - ) - .context("Error creating 3D Texture repo")?; // TODO - - debug!("Creating UI Texture Repo"); - let ui_tex_repo = TextureRepo::new( - device_lock.clone(), - queue_negotiator - .family::<TexLoadQueue>() - .ok_or(EnvironmentError::NoQueues)?, - queue_negotiator - .get_queue::<TexLoadQueue>(&mut queue_groups) - .ok_or(EnvironmentError::NoQueues) - .context("Error getting UI texture loader queue")?, - &adapter, - TextureLoadConfig { - resolver: UiTextures::new(ui.ctx().clone()), - filter: hal::image::Filter::Linear, - wrap_mode: hal::image::WrapMode::Clamp, - }, - ) - .context("Error creating UI texture repo")?; // TODO - - let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?; - - let ds_layout_lock = tex_repo.get_ds_layout()?; - let ui_ds_layout_lock = ui_tex_repo.get_ds_layout()?; - - // Graphics pipeline - let pipeline = CompletePipeline::new( - &mut device, - swapchain_properties.extent, - &swapchain_properties, - once(&*ds_layout_lock), - )?; - - // UI pipeline - let ui_pipeline = UiPipeline::new( - &mut device, - swapchain_properties.extent, - &swapchain_properties, - once(&*ui_ds_layout_lock), - )?; - // Swapchain and associated resources let target_chain = TargetChain::new( &mut device, &adapter, surface, - &pipeline, - &ui_pipeline, &mut cmd_pool, swapchain_properties, ) .context("Error creating target chain")?; + // Unlock device drop(device); - drop(ds_layout_lock); - drop(ui_ds_layout_lock); Ok(RenderingContext { map, @@ -256,18 +185,10 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { .ok_or(EnvironmentError::NoQueues) .context("Error getting draw queue")?, + draw_pass: ManuallyDrop::new(dp), target_chain: ManuallyDrop::new(target_chain), cmd_pool: ManuallyDrop::new(cmd_pool), - pipeline: ManuallyDrop::new(pipeline), - ui_pipeline: ManuallyDrop::new(ui_pipeline), - - tex_repo: ManuallyDrop::new(tex_repo), - ui_tex_repo: ManuallyDrop::new(ui_tex_repo), - - draw_buffers: ManuallyDrop::new(draw_buffers), - ui_draw_buffers: ManuallyDrop::new(ui_draw_buffers), - vp_matrix: Mat4::identity(), // pixels_per_point: window.scale_factor() as f32, @@ -295,47 +216,13 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { let properties = SwapchainProperties::find_best(&self.adapter, &surface) .context("Error finding best swapchain properties")?; - use core::ptr::read; - - // Graphics pipeline - // TODO: Recycle - let ds_layout_handle = self.tex_repo.get_ds_layout()?; - let ui_ds_layout_handle = self.tex_repo.get_ds_layout()?; - - ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut device); - self.pipeline = ManuallyDrop::new({ - CompletePipeline::new( - &mut device, - properties.extent, - &properties, - once(&*ds_layout_handle), - ) - .context("Error creating 3D Pipeline")? - }); - - // 2D Graphics pipeline - // TODO: Recycle - ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut device); - self.ui_pipeline = ManuallyDrop::new({ - let mut descriptor_set_layouts: ArrayVec<[_; 1]> = ArrayVec::new(); - descriptor_set_layouts.push(&*ui_ds_layout_handle); - - UiPipeline::new( - &mut device, - properties.extent, - &properties, - once(&*ui_ds_layout_handle), - ) - .context("Error creating UI Pipeline")? - }); + // TODO: Notify draw passes self.target_chain = ManuallyDrop::new( TargetChain::new( &mut device, &self.adapter, surface, - &self.pipeline, - &self.ui_pipeline, &mut self.cmd_pool, properties, ) @@ -345,7 +232,7 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { } /// Draw all vertices in the buffer - pub fn draw_vertices(&mut self, ui: &mut UiState, faces: &[u32]) -> Result<()> { + pub fn draw_next_frame(&mut self) -> Result<()> { let mut device = self .device .write() @@ -356,95 +243,26 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { .write() .map_err(|_| LockPoisoned::Map) .context("Error getting map lock")?; + let map = self.map.read().or(Err(LockPoisoned::Map))?; - // Ensure UI texture(s) are loaded - ensure_textures_ui(&mut self.ui_tex_repo, ui)?; - - // Get any textures that just finished loading - self.ui_tex_repo.process_responses(); - self.tex_repo.process_responses(); - - // 3D Pass - let (cmd_buffer, img) = self - .target_chain - .prep_next_target( - &mut device, - &mut self.draw_buffers, - &self.pipeline, - &self.vp_matrix, - ) - .context("Error preparing next target")?; - - do_render( - cmd_buffer, - &mut self.draw_buffers, - &mut self.tex_repo, - &self.pipeline.pipeline_layout, - &*self - .map - .read() - .map_err(|_| LockPoisoned::Map) - .context("Error getting map read lock")?, - faces, - )?; - - // 2D Pass - let cmd_buffer = self - .target_chain - .target_2d_pass(&mut self.ui_draw_buffers, &img, &self.ui_pipeline) - .context("Error switching to 2D pass")?; - - do_render_ui( - cmd_buffer, - &self.ui_pipeline.pipeline_layout, - &mut self.ui_draw_buffers, - &mut self.ui_tex_repo, - ui, - )?; - - // Update our buffers before we actually start drawing - self.draw_buffers - .vertex_buffer - .commit(&device, &mut queue, &mut self.cmd_pool)?; - - self.draw_buffers - .index_buffer - .commit(&device, &mut queue, &mut self.cmd_pool)?; - - self.ui_draw_buffers - .vertex_buffer - .commit(&device, &mut queue, &mut self.cmd_pool)?; - - self.ui_draw_buffers - .index_buffer - .commit(&device, &mut queue, &mut self.cmd_pool)?; - - // Send commands off to GPU + // Level draw pass self.target_chain - .finish_and_submit_target(img, &mut queue) - .context("Error finishing and submitting target")?; + .do_draw_with(&mut device, &mut queue, &*self.draw_pass, &*map) + .context("Error preparing next target")?; Ok(()) } } -impl<'a, M: MinBspFeatures<VulkanSystem>> core::ops::Drop for RenderingContext<'a, M> { +impl<M: 'static + MinRenderFeatures, LDP> core::ops::Drop for RenderingContext<M, LDP> { fn drop(&mut self) { { self.device.write().unwrap().wait_idle().unwrap(); } unsafe { - use core::ptr::read; - - ManuallyDrop::into_inner(read(&self.tex_repo)).deactivate(&mut self.device); - ManuallyDrop::into_inner(read(&self.ui_tex_repo)).deactivate(&mut self.device); - let mut device = self.device.write().unwrap(); - ManuallyDrop::into_inner(read(&self.draw_buffers)).deactivate(&mut device); - ManuallyDrop::into_inner(read(&self.ui_draw_buffers)).deactivate(&mut device); - ManuallyDrop::into_inner(read(&self.target_chain)).deactivate( &mut self.instance, &mut device, @@ -452,9 +270,6 @@ impl<'a, M: MinBspFeatures<VulkanSystem>> core::ops::Drop for RenderingContext<' ); device.destroy_command_pool(ManuallyDrop::into_inner(read(&self.cmd_pool))); - - ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut device); - ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut device); } } } |