diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:20 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:20 +0100 |
commit | b31035bf03e0843fb516bee065f9a010424ba546 (patch) | |
tree | b98e55478f47da33e6f1faa994da6b91b97b9ad2 /stockton-render | |
parent | a748e4c3e3615601ee2afe6d347ef439d8ff50fa (diff) |
refactor(render): update gfx-hal and use staging and index buffers.
also some minor changes to types because of deprecation
and a bunch of readability improvements
Diffstat (limited to 'stockton-render')
-rw-r--r-- | stockton-render/Cargo.toml | 3 | ||||
-rw-r--r-- | stockton-render/src/draw/buffer.rs | 158 | ||||
-rw-r--r-- | stockton-render/src/draw/context.rs | 1092 | ||||
-rw-r--r-- | stockton-render/src/draw/mod.rs | 2 | ||||
-rw-r--r-- | stockton-render/src/error.rs | 1 | ||||
-rw-r--r-- | stockton-render/src/lib.rs | 42 | ||||
-rw-r--r-- | stockton-render/src/types.rs | 36 |
7 files changed, 714 insertions, 620 deletions
diff --git a/stockton-render/Cargo.toml b/stockton-render/Cargo.toml index eb717c4..d207159 100644 --- a/stockton-render/Cargo.toml +++ b/stockton-render/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Oscar <oscar.shrimpton.personal@gmail.com>"] [dependencies] stockton-types = { path = "../stockton-types" } -winit = "0.19.1" +winit = "^0.21" gfx-hal = "^0.5" arrayvec = "0.4.10" nalgebra-glm = "0.4.0" @@ -18,4 +18,5 @@ vulkan = ["gfx-backend-vulkan"] [dependencies.gfx-backend-vulkan] version = "^0.5" +features = ["x11"] optional = true diff --git a/stockton-render/src/draw/buffer.rs b/stockton-render/src/draw/buffer.rs index d29f857..f420fc7 100644 --- a/stockton-render/src/draw/buffer.rs +++ b/stockton-render/src/draw/buffer.rs @@ -13,26 +13,28 @@ // You should have received a copy of the GNU General Public License along // with this program. If not, see <http://www.gnu.org/licenses/>. -use std::marker::PhantomData; -use std::ops::{Index, IndexMut, Range}; +use std::ops::{Index, IndexMut}; use std::convert::TryInto; use core::mem::{ManuallyDrop, size_of}; -use hal::memory::{Properties, Requirements, Segment}; -use hal::buffer::Usage; -use hal::adapter::{Adapter, MemoryType, PhysicalDevice}; -use hal::device::Device; -use hal::{MemoryTypeId, VertexCount, InstanceCount}; -use hal::Backend; + +use hal::prelude::*; +use hal::{ + MemoryTypeId, + buffer::Usage, + memory::{Properties, Segment}, + queue::Submission +}; + use crate::error::CreationError; -use super::RenderingContext; +use crate::types::*; // TODO: Proper sizing of buffers -const BUF_SIZE: u64 = 32; +const BUF_SIZE: u64 = 4 * 15 * 2; -fn create_buffer(device: &mut <back::Backend as hal::Backend>::Device, - adapter: &Adapter<back::Backend>, +fn create_buffer(device: &mut Device, + adapter: &Adapter, usage: Usage, - properties: Properties) -> Result<(<back::Backend as hal::Backend>::Buffer, <back::Backend as hal::Backend>::Memory), CreationError> { + properties: Properties) -> Result<(Buffer, Memory), CreationError> { let mut buffer = unsafe { device .create_buffer(BUF_SIZE, usage) } .map_err(|e| CreationError::BufferError (e))?; @@ -59,66 +61,131 @@ fn create_buffer(device: &mut <back::Backend as hal::Backend>::Device, )) } -trait ModifiableBuffer: IndexMut<usize> { - fn commit<'a>(&'a self) -> &'a <back::Backend as hal::Backend>::Buffer; +pub trait ModifiableBuffer: IndexMut<usize> { + fn commit<'a>(&'a mut self, device: &Device, + command_queue: &mut CommandQueue, + command_pool: &mut CommandPool) -> &'a Buffer; } -pub struct StagedBuffer<'a> { - stagedBuffer: ManuallyDrop<<back::Backend as hal::Backend>::Buffer>, - stagedMemory: ManuallyDrop<<back::Backend as hal::Backend>::Memory>, - buffer: ManuallyDrop<<back::Backend as hal::Backend>::Buffer>, - memory: ManuallyDrop<<back::Backend as hal::Backend>::Memory>, - mappedStaged: &'a mut [f32], - stagedIsDirty: bool +pub struct StagedBuffer<'a, T: Sized> { + staged_buffer: ManuallyDrop<Buffer>, + staged_memory: ManuallyDrop<Memory>, + buffer: ManuallyDrop<Buffer>, + memory: ManuallyDrop<Memory>, + staged_mapped_memory: &'a mut [T], + staged_is_dirty: bool, } -impl<'a> ModifiableBuffer for StagedBuffer<'a> { - fn new(device: &mut <back::Backend as hal::Backend>::Device, adapter: &Adapter<back::Backend>, usage: Usage) -> Result<Self, CreationError> { +impl<'a, T: Sized> StagedBuffer<'a, T> { + pub fn new(device: &mut Device, adapter: &Adapter, usage: Usage) -> Result<Self, CreationError> { - let (stagedBuffer, stagedMemory) = create_buffer(device, adapter, Usage::TRANSFER_SRC, Properties::CPU_VISIBLE)?; + let (staged_buffer, staged_memory) = create_buffer(device, adapter, Usage::TRANSFER_SRC, Properties::CPU_VISIBLE)?; let (buffer, memory) = create_buffer(device, adapter, Usage::TRANSFER_DST | usage, Properties::DEVICE_LOCAL)?; // Map it somewhere and get a slice to that memory - let rawPtr = unsafe { - device.map_memory(&stagedMemory, Segment::ALL).unwrap() // TODO + let staged_mapped_memory = unsafe { + let ptr = device.map_memory(&staged_memory, Segment::ALL).unwrap(); + + let slice_size: usize = (BUF_SIZE / size_of::<T>() as u64).try_into().unwrap(); // size in f32s + + std::slice::from_raw_parts_mut(ptr as *mut T, slice_size) }; - let sliceSize: usize = (BUF_SIZE / 4).try_into().unwrap(); // size in f32s - let mappedStaged: &'a mut [f32] = std::slice::from_raw_parts_mut(rawPtr as *mut f32, sliceSize); Ok(StagedBuffer { - stagedBuffer: ManuallyDrop::new(stagedBuffer), - stagedMemory: ManuallyDrop::new(stagedMemory), + staged_buffer: ManuallyDrop::new(staged_buffer), + staged_memory: ManuallyDrop::new(staged_memory), buffer: ManuallyDrop::new(buffer), memory: ManuallyDrop::new(memory), - mappedStaged: mappedStaged, - stagedIsDirty: false + staged_mapped_memory, + staged_is_dirty: false }) } + + pub(crate) fn deactivate(mut self, device: &mut Device) { + unsafe { + device.unmap_memory(&self.staged_memory); + + device.free_memory(ManuallyDrop::take(&mut self.staged_memory)); + device.destroy_buffer(ManuallyDrop::take(&mut self.staged_buffer)); + + device.free_memory(ManuallyDrop::take(&mut self.memory)); + device.destroy_buffer(ManuallyDrop::take(&mut self.buffer)); + }; + } +} + +impl <'a, T: Sized> ModifiableBuffer for StagedBuffer<'a, T> { + fn commit<'b>(&'b mut self, device: &Device, + command_queue: &mut CommandQueue, + command_pool: &mut CommandPool) -> &'b Buffer { + if self.staged_is_dirty { + // Copy from staged to buffer + + let buf = unsafe { + use hal::command::{CommandBufferFlags, BufferCopy}; + // Get a command buffer + let mut buf = command_pool.allocate_one(hal::command::Level::Primary); + + // Put in our copy command + buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); + buf.copy_buffer(&self.staged_buffer, &self.buffer, &[ + BufferCopy { + src: 0, + dst: 0, + size: BUF_SIZE // TODO + } + ]); + buf.finish(); + + buf + }; + + // Submit it and wait for completion + // TODO: We could use more semaphores or something? + // TODO: Better error handling + unsafe { + let copy_finished = device.create_fence(false).unwrap(); + command_queue.submit::<_, _, Semaphore, _, _>(Submission { + command_buffers: &[&buf], + wait_semaphores: std::iter::empty::<_>(), + signal_semaphores: std::iter::empty::<_>() + }, Some(©_finished)); + + device + .wait_for_fence(©_finished, core::u64::MAX).unwrap(); + device.destroy_fence(copy_finished); + } + + self.staged_is_dirty = false; + } + + &self.buffer + } } -impl<'a> Index<usize> for StagedBuffer<'a> { - type Output = f32; +impl<'a, T: Sized> Index<usize> for StagedBuffer<'a, T> { + type Output = T; fn index(&self, index: usize) -> &Self::Output { - &self.mappedStaged[index] + &self.staged_mapped_memory[index] } } -impl<'a> IndexMut<usize> for StagedBuffer<'a> { +impl<'a, T: Sized> IndexMut<usize> for StagedBuffer<'a, T> { fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.stagedIsDirty = true; - &mut self.mappedStaged[index] + self.staged_is_dirty = true; + &mut self.staged_mapped_memory[index] } } // trait VertexLump { -// pub fn new(device: &mut <back::Backend as hal::Backend>::Device, adapter: &Adapter<back::Backend>) -> Result<Self, CreationError> { +// pub fn new(device: &mut Device, adapter: &Adapter<back::Backend>) -> Result<Self, CreationError> { // } // pub(crate) struct VertexLump<T: Into<X>, X: Pod> { -// pub (crate) buffer: ManuallyDrop<<back::Backend as hal::Backend>::Buffer>, -// memory: ManuallyDrop<<back::Backend as hal::Backend>::Memory>, +// pub (crate) buffer: ManuallyDrop<Buffer>, +// memory: ManuallyDrop<Memory>, // requirements: Requirements, // unit_size_bytes: u64, @@ -141,7 +208,7 @@ impl<'a> IndexMut<usize> for StagedBuffer<'a> { // const BATCH_SIZE: u64 = 3; // impl<T: Into<X>, X: Pod> VertexLump<T, X> { -// pub fn new(device: &mut <back::Backend as hal::Backend>::Device, adapter: &Adapter<back::Backend>) -> Result<VertexLump<T, X>, CreationError> { +// pub fn new(device: &mut Device, adapter: &Adapter<back::Backend>) -> Result<VertexLump<T, X>, CreationError> { // let unit_size_bytes = size_of::<X>() as u64; // let unit_size_verts = unit_size_bytes / size_of::<f32>() as u64; @@ -286,10 +353,5 @@ impl<'a> IndexMut<usize> for StagedBuffer<'a> { // }) // } -// pub(crate) fn deactivate(&mut self, ctx: &mut RenderingContext) { -// unsafe { ctx.device.free_memory(ManuallyDrop::take(&mut self.memory)) }; -// unsafe { ctx.device.destroy_buffer(ManuallyDrop::take(&mut self.buffer)) }; -// self.active = false; -// } // } diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs index 53f92cf..7a20651 100644 --- a/stockton-render/src/draw/context.rs +++ b/stockton-render/src/draw/context.rs @@ -14,239 +14,210 @@ // with this program. If not, see <http://www.gnu.org/licenses/>. //! Deals with all the Vulkan/HAL details. -use crate::error as error; -use crate::error::{CreationError, FrameError}; +//! In the end, this takes in vertices and renders them to a window. +//! You'll need something else to actually generate the vertices though. use std::mem::{ManuallyDrop, size_of}; -use std::convert::TryInto; - -use winit::{EventsLoop, WindowBuilder}; - +use winit::window::Window; use arrayvec::ArrayVec; -use hal::*; -use hal::device::Device; -use hal::format::{AsFormat, Rgba8Srgb as ColorFormat, Format, ChannelType}; -use hal::pool::CommandPool; -use hal::queue::{QueueGroup, Submission}; -use hal::window::SwapchainConfig; - -use hal::Instance as InstanceTrait; - -#[cfg(feature = "gl")] -use back::glutin as glutin; - -use stockton_types::Vector2; -use super::buffer::StagedBuffer; +use hal::{ + prelude::*, + queue::{Submission}, + window::SwapchainConfig +}; +use stockton_types::{Vector2, Vector3}; -type ModifiableBuffer<'a> = StagedBuffer<'a>; +use crate::types::*; +use crate::error; +use super::buffer::{StagedBuffer, ModifiableBuffer}; +/// Entry point name for shaders const ENTRY_NAME: &str = "main"; -const COLOR_RANGE: image::SubresourceRange = image::SubresourceRange { - aspects: format::Aspects::COLOR, - levels: 0..1, - layers: 0..1, + +/// Defines the colour range we use. +const COLOR_RANGE: hal::image::SubresourceRange = hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: 0..1, + layers: 0..1, }; +/// Source for vertex shader. TODO const VERTEX_SOURCE: &str = include_str!("./data/stockton.vert"); -const FRAGMENT_SOURCE: &str = include_str!("./data/stockton.frag"); -const VERTEX_BUFFER_BATCH_SIZE: u64 = 10; -const VERTEX_BUFFER_INITIAL_BATCHES: u64 = 1; +/// Source for fragment shader. TODO +const FRAGMENT_SOURCE: &str = include_str!("./data/stockton.frag"); -/// Represents a triangle in 2D (screen) space. +/// Represents a point of a vertices, including U/V information. #[derive(Debug, Clone, Copy)] -pub struct Tri2 (pub [Vector2; 3]); - -/// Easy conversion to proper format. -impl From<Tri2> for [f32; 15] { - fn from(tri: Tri2) -> [f32; 15] { - [tri.0[0].x, tri.0[0].y, 1.0, 0.0, 0.0, - tri.0[1].x, tri.0[1].y, 0.0, 1.0, 0.0, - tri.0[2].x, tri.0[2].y, 0.0, 0.0, 1.0] - } -} - -const TRI2_SIZE_F32: usize = 15; -const TRI2_SIZE_BYTES: usize = size_of::<f32>() * TRI2_SIZE_F32; - -#[cfg(not(feature = "gl"))] -type Instance = back::Instance; - -#[cfg(feature = "gl")] -type Instance = (); +pub struct UVPoint (pub Vector2, pub Vector3); /// Contains all the hal related stuff. /// In the end, this takes some 3D points and puts it on the screen. // TODO: Settings for clear colour, buffer sizes, etc pub struct RenderingContext<'a> { - pub events_loop: winit::EventsLoop, - surface: <back::Backend as hal::Backend>::Surface, + // Parents for most of these things + instance: ManuallyDrop<back::Instance>, + device: ManuallyDrop<Device>, + + // Render destination + surface: ManuallyDrop<Surface>, + swapchain: ManuallyDrop<Swapchain>, + viewport: hal::pso::Viewport, + + imageviews: Vec<ImageView>, + framebuffers: Vec<Framebuffer>, + current_frame: usize, + frames_in_flight: usize, + + // Sync objects + // TODO: Collect these together? + get_image: Vec<Semaphore>, + render_complete: Vec<Semaphore>, + present_complete: Vec<Fence>, + + // Pipeline + renderpass: ManuallyDrop<RenderPass>, + descriptor_set_layouts: ManuallyDrop<DescriptorSetLayout>, + pipeline_layout: ManuallyDrop<PipelineLayout>, + pipeline: ManuallyDrop<GraphicsPipeline>, + + // Command pool and buffers + cmd_pool: ManuallyDrop<CommandPool>, + cmd_buffers: Vec<CommandBuffer>, + queue_group: QueueGroup, + + // Vertex and index buffers + // These are both staged + pub vert_buffer: ManuallyDrop<StagedBuffer<'a, UVPoint>>, + pub index_buffer: ManuallyDrop<StagedBuffer<'a, (u16, u16, u16)>>, +} - pub (crate) instance: ManuallyDrop<Instance>, - pub (crate) device: ManuallyDrop<<back::Backend as hal::Backend>::Device>, +impl<'a> RenderingContext<'a> { + /// Create a new RenderingContext for the given window. + pub fn new(window: &Window) -> Result<Self, error::CreationError> { + // Create surface + let (instance, mut surface, mut adapters) = unsafe { + use hal::Instance; - swapchain: ManuallyDrop<<back::Backend as hal::Backend>::Swapchain>, - - viewport: pso::Viewport, + let instance = back::Instance::create("stockton", 1).map_err(|_| error::CreationError::WindowError)?; + let surface = instance.create_surface(window).map_err(|_| error::CreationError::WindowError)?; + let adapters = instance.enumerate_adapters(); - imageviews: Vec<<back::Backend as hal::Backend>::ImageView>, - framebuffers: Vec<<back::Backend as hal::Backend>::Framebuffer>, + (instance, surface, adapters) + }; - renderpass: ManuallyDrop<<back::Backend as hal::Backend>::RenderPass>, + // TODO: Properly figure out which adapter to use + let adapter = adapters.remove(0); + + // Device & Queue group + let (mut device, queue_group) = { + let family = adapter + .queue_families + .iter() + .find(|family| { + surface.supports_queue_family(family) && family.queue_type().supports_graphics() + }) + .unwrap(); + + let mut gpu = unsafe { + adapter + .physical_device + .open(&[(family, &[1.0])], hal::Features::empty()) + .unwrap() + }; - current_frame: usize, - // TODO: Collect these together - get_image: Vec<<back::Backend as hal::Backend>::Semaphore>, - render_complete: Vec<<back::Backend as hal::Backend>::Semaphore>, - present_complete: Vec<<back::Backend as hal::Backend>::Fence>, + (gpu.device, gpu.queue_groups.pop().unwrap()) + }; - frames_in_flight: usize, - cmd_pools: Vec<ManuallyDrop<<back::Backend as hal::Backend>::CommandPool>>, - cmd_buffers: Vec<<back::Backend as hal::Backend>::CommandBuffer>, - queue_group: QueueGroup<back::Backend>, + // Swapchain + let (format, viewport, extent, swapchain, backbuffer) = { + use hal::{ + window::{PresentMode, CompositeAlphaMode}, + format::{Format, ChannelType}, + image::Usage, + pso::Viewport + }; - vert_buffer: ModifiableBuffer<'a>, - index_buffer: ModifiableBuffer<'a>, + // Figure out what the surface supports + let caps = surface.capabilities(&adapter.physical_device); + let formats = surface.supported_formats(&adapter.physical_device); + + // Find which settings we'll actually use based on preset preferences + let format = formats.map_or(Format::Rgba8Srgb, |formats| { + formats.iter() + .find(|format| format.base_format().1 == ChannelType::Srgb) + .map(|format| *format) + .unwrap_or(formats[0]) + }); + + let present_mode = { + [PresentMode::MAILBOX, PresentMode::FIFO, PresentMode::RELAXED, PresentMode::IMMEDIATE] + .iter() + .cloned() + .find(|pm| caps.present_modes.contains(*pm)) + .ok_or(error::CreationError::BadSurface)? + }; + let composite_alpha = { + [CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT, CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED] + .iter() + .cloned() + .find(|ca| caps.composite_alpha_modes.contains(*ca)) + .ok_or(error::CreationError::BadSurface)? + }; - descriptor_set_layouts: <back::Backend as hal::Backend>::DescriptorSetLayout, - pipeline_layout: ManuallyDrop<<back::Backend as hal::Backend>::PipelineLayout>, - pipeline: ManuallyDrop<<back::Backend as hal::Backend>::GraphicsPipeline>, - pub (crate) adapter: adapter::Adapter<back::Backend> -} + // Figure out properties for our swapchain + let extent = caps.extents.end(); // Size -impl<'a> RenderingContext<'a> { - /// Create a new RenderingContext for the given window. - pub fn new() -> Result<Self, CreationError> { - let events_loop = EventsLoop::new(); - let wb = WindowBuilder::new(); - - // Create surface - #[cfg(not(feature = "gl"))] - let (window, instance, mut surface, mut adapters) = { - use hal::Instance; - let window = wb.build(&events_loop).map_err(|_| CreationError::WindowError)?; - let instance = back::Instance::create("stockton", 1); - let surface = instance.create_surface(&window); - let adapters = instance.enumerate_adapters(); - - (window, instance, surface, adapters) - }; - - #[cfg(feature = "gl")] - let (window, instance, mut surface, mut adapters) = { - use back::glutin::ContextBuilder; - - let glutin_window = ContextBuilder::new().with_vsync(true).build_windowed(wb, &events_loop).unwrap(); - let (glutin_context, glutin_window) = unsafe { - glutin_window.make_current().map_err(|_| CreationError::WindowError)? - .split() + // Number of frames to pre-render + let image_count = if present_mode == PresentMode::MAILBOX { + ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(3)) + } else { + ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(2)) }; - let surface = back::Surface::from_context(glutin_context); - let adapters = surface.enumerate_adapters(); - - ((), (), surface, adapters) - }; - - // TODO: Properly figure out which adapter to use - let mut adapter = adapters.remove(0); - - // Device & Queue group - let (mut device, queue_group) = { - // TODO - let family = adapter - .queue_families - .iter() - .find(|family| { - surface.supports_queue_family(family) && family.queue_type().supports_graphics() - }) - .unwrap(); - - let mut gpu = unsafe { - adapter - .physical_device - .open(&[(family, &[1.0])], hal::Features::empty()) - .unwrap() - }; - - (gpu.queue_groups.pop().unwrap(), gpu.device) - }; - - // Swapchain stuff - let (format, viewport, extent, swapchain, backbuffer) = { - use hal::window::{PresentMode, CompositeAlphaMode}; - - let (caps, formats, present_modes) = surface.compatibility(&mut adapter.physical_device); - - let format = formats.map_or(Format::Rgba8Srgb, |formats| { - formats.iter() - .find(|format| format.base_format().1 == ChannelType::Srgb) - .map(|format| *format) - .unwrap_or(formats[0]) - }); - - let present_mode = { - [PresentMode::Mailbox, PresentMode::Fifo, PresentMode::Relaxed, PresentMode::Immediate] - .iter() - .cloned() - .find(|pm| present_modes.contains(pm)) - .ok_or(CreationError::BadSurface)? - }; - let composite_alpha = { - [CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT, CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED] - .iter() - .cloned() - .find(|ca| caps.composite_alpha.contains(*ca)) - .ok_or(CreationError::BadSurface)? - }; - - let extent = caps.extents.end(); - let image_count = if present_mode == PresentMode::Mailbox { - ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(3)) - } else { - ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(2)) - }; - - let image_layers = 1; - let image_usage = if caps.usage.contains(image::Usage::COLOR_ATTACHMENT) { - image::Usage::COLOR_ATTACHMENT - } else { - Err(CreationError::BadSurface)? + let image_layers = 1; // Don't support 3D + let image_usage = if caps.usage.contains(Usage::COLOR_ATTACHMENT) { + Usage::COLOR_ATTACHMENT + } else { + Err(error::CreationError::BadSurface)? }; - // Swap config - let swap_config = SwapchainConfig { - present_mode, - composite_alpha, - format, - extent: *extent, - image_count, - image_layers, - image_usage, + // Swap config + let swap_config = SwapchainConfig { + present_mode, + composite_alpha_mode: composite_alpha, + format, + extent: *extent, + image_count, + image_layers, + image_usage, }; - // Viewport - let extent = extent.to_extent(); - let viewport = pso::Viewport { - rect: extent.rect(), - depth: 0.0..1.0 - }; - - // Swapchain - let (swapchain, backbuffer) = unsafe { - device.create_swapchain(&mut surface, swap_config, None) - .map_err(|e| CreationError::SwapchainError (e))? - }; - - (format, viewport, extent, swapchain, backbuffer) - }; + // Viewport + let extent = extent.to_extent(); + let viewport = Viewport { + rect: extent.rect(), + depth: 0.0..1.0 + }; + + // Swapchain + let (swapchain, backbuffer) = unsafe { + device.create_swapchain(&mut surface, swap_config, None) + .map_err(|e| error::CreationError::SwapchainError (e))? + }; + + (format, viewport, extent, swapchain, backbuffer) + }; // Renderpass let renderpass = { - use hal::pass::*; - use hal::pso::PipelineStage; - use hal::image::{Access, Layout}; + use hal::{ + pass::*, + pso::PipelineStage, + image::{Access, Layout}, + memory::Dependencies + }; let attachment = Attachment { format: Some(format), @@ -265,127 +236,135 @@ impl<'a> RenderingContext<'a> { }; let dependency = SubpassDependency { - passes: None..0, + flags: Dependencies::empty(), + passes: None..Some(0), stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT..PipelineStage::COLOR_ATTACHMENT_OUTPUT, accesses: Access::empty() - ..(Access::COLOR_ATTACHMENT_READ | Access::COLOR_ATTACHMENT_WRITE) + ..(Access::COLOR_ATTACHMENT_READ | Access::COLOR_ATTACHMENT_WRITE) }; unsafe { device.create_render_pass(&[attachment], &[subpass], &[dependency]) } - .map_err(|_| CreationError::OutOfMemoryError)? + .map_err(|_| error::CreationError::OutOfMemoryError)? }; // Subpass - let subpass = pass::Subpass { + let subpass = hal::pass::Subpass { index: 0, main_pass: &renderpass }; - // Vertex and index buffers - let (vert_buffer, index_buffer) = { - use hal::buffer::Usage; - ( - ModifiableBuffer::new(&mut device, &adapter, Usage::VERTEX | Usage::TRANSFER_DST), - ModifiableBuffer::new(&mut device, &adapter, Usage::TRANSFER_SRC) - ) - }; - - // Command Pools, Buffers, imageviews, framebuffers & Sync objects - let frames_in_flight = backbuffer.len(); - let (cmd_pools, cmd_buffers, get_image, render_complete, present_complete, imageviews, framebuffers) = { - let mut cmd_pools = Vec::with_capacity(frames_in_flight); - let mut cmd_buffers = Vec::with_capacity(frames_in_flight); - let mut get_image = Vec::with_capacity(frames_in_flight); - let mut render_complete = Vec::with_capacity(frames_in_flight); - let mut present_complete = Vec::with_capacity(frames_in_flight); - let mut imageviews = Vec::with_capacity(frames_in_flight); - let mut framebuffers = Vec::with_capacity(frames_in_flight); - - for i in 0..frames_in_flight { - cmd_pools.push(ManuallyDrop::new(unsafe { - device.create_command_pool_typed(&queue_group, pool::CommandPoolCreateFlags::empty()) - }.map_err(|_| CreationError::OutOfMemoryError)?)); - - cmd_buffers.push((*cmd_pools[i]).allocate_one(hal::command::Level::Primary)); - get_image.push(device.create_semaphore().map_err(|_| CreationError::SyncObjectError)?); - render_complete.push(device.create_semaphore().map_err(|_| CreationError::SyncObjectError)?); - present_complete.push(device.create_fence(true).map_err(|_| CreationError::SyncObjectError)?); - - unsafe { - imageviews.push(device.create_image_view( - &backbuffer[i], - image::ViewKind::D2, - format, - format::Swizzle::NO, - COLOR_RANGE.clone(), - ).map_err(|e| CreationError::ImageViewError (e))?); - framebuffers.push(device.create_framebuffer( - &renderpass, - Some(&imageviews[i]), - extent - ).map_err(|_| CreationError::OutOfMemoryError)?); - } - } - - (cmd_pools, cmd_buffers, get_image, render_complete, present_complete, imageviews, framebuffers) - }; - - // Graphics pipeline - let (descriptor_set_layouts, pipeline_layout, pipeline) = Self::create_pipeline(&mut device, extent, &subpass)?; - - Ok(RenderingContext { - instance: ManuallyDrop::new(instance), - events_loop, - surface, - - device: ManuallyDrop::new(device), - queue_group, - swapchain: ManuallyDrop::new(swapchain), - viewport, - - imageviews, - framebuffers, - - renderpass: ManuallyDrop::new(renderpass), - current_frame: 0, - - get_image, - render_complete, - present_complete, - frames_in_flight, - cmd_pools, - cmd_buffers, - - descriptor_set_layouts: descriptor_set_layouts, - pipeline_layout: ManuallyDrop::new(pipeline_layout), - pipeline: ManuallyDrop::new(pipeline), - - vert_buffer, - index_buffer, - - adapter - }) + // Vertex and index buffers + let (vert_buffer, index_buffer) = { + use hal::buffer::Usage; + + let vert = StagedBuffer::new(&mut device, &adapter, Usage::VERTEX | Usage::TRANSFER_DST)?; + let index = StagedBuffer::new(&mut device, &adapter, Usage::TRANSFER_SRC)?; + + (vert, index) + }; + + // Command Pool, Buffers, imageviews, framebuffers & Sync objects + let frames_in_flight = backbuffer.len(); + let (cmd_pool, cmd_buffers, get_image, render_complete, present_complete, imageviews, framebuffers) = { + use hal::pool::CommandPoolCreateFlags; + use hal::command::Level; + + let mut cmd_pool = ManuallyDrop::new(unsafe { + device.create_command_pool(queue_group.family, CommandPoolCreateFlags::empty()) + }.map_err(|_| error::CreationError::OutOfMemoryError)?); + + let mut cmd_buffers = Vec::with_capacity(frames_in_flight); + let mut get_image = Vec::with_capacity(frames_in_flight); + let mut render_complete = Vec::with_capacity(frames_in_flight); + let mut present_complete = Vec::with_capacity(frames_in_flight); + let mut imageviews = Vec::with_capacity(frames_in_flight); + let mut framebuffers = Vec::with_capacity(frames_in_flight); + + for i in 0..frames_in_flight { + unsafe { + cmd_buffers.push(cmd_pool.allocate_one(Level::Primary)); // TODO: We can do this all at once outside the loop + } + + get_image.push(device.create_semaphore().map_err(|_| error::CreationError::SyncObjectError)?); + render_complete.push(device.create_semaphore().map_err(|_| error::CreationError::SyncObjectError)?); + present_complete.push(device.create_fence(true).map_err(|_| error::CreationError::SyncObjectError)?); + + unsafe { + use hal::image::ViewKind; + use hal::format::Swizzle; + + imageviews.push(device.create_image_view( + &backbuffer[i], + ViewKind::D2, + format, + Swizzle::NO, + COLOR_RANGE.clone(), + ).map_err(|e| error::CreationError::ImageViewError (e))?); + framebuffers.push(device.create_framebuffer( + &renderpass, + Some(&imageviews[i]), + extent + ).map_err(|_| error::CreationError::OutOfMemoryError)?); + } + } + + (cmd_pool, cmd_buffers, get_image, render_complete, present_complete, imageviews, framebuffers) + }; + + // Graphics pipeline + let (descriptor_set_layouts, pipeline_layout, pipeline) = Self::create_pipeline(&mut device, extent, &subpass)?; + + Ok(RenderingContext { + instance: ManuallyDrop::new(instance), + surface: ManuallyDrop::new(surface), + + device: ManuallyDrop::new(device), + queue_group, + swapchain: ManuallyDrop::new(swapchain), + viewport, + + imageviews, + framebuffers, + + renderpass: ManuallyDrop::new(renderpass), + current_frame: 0, + + get_image, + render_complete, + present_complete, + frames_in_flight, + cmd_pool, + cmd_buffers, + + descriptor_set_layouts: ManuallyDrop::new(descriptor_set_layouts), + pipeline_layout: ManuallyDrop::new(pipeline_layout), + pipeline: ManuallyDrop::new(pipeline), + + vert_buffer: ManuallyDrop::new(vert_buffer), + index_buffer: ManuallyDrop::new(index_buffer), + }) } #[allow(clippy::type_complexity)] - pub fn create_pipeline(device: &mut <back::Backend as hal::Backend>::Device, extent: image::Extent, subpass: &pass::Subpass<back::Backend>) -> Result< - ( - <back::Backend as hal::Backend>::DescriptorSetLayout, - <back::Backend as hal::Backend>::PipelineLayout, - <back::Backend as hal::Backend>::GraphicsPipeline, - ), error::CreationError> { - use hal::pso::*; - - // Shader modules - let (vs_module, fs_module) = { + pub fn create_pipeline(device: &mut Device, extent: hal::image::Extent, subpass: &hal::pass::Subpass<back::Backend>) -> Result< + ( + DescriptorSetLayout, + PipelineLayout, + GraphicsPipeline, + ), error::CreationError> { + use hal::pso::*; + use hal::format::Format; + + // Shader modules + let (vs_module, fs_module) = { let mut compiler = shaderc::Compiler::new().ok_or(error::CreationError::NoShaderC)?; let vertex_compile_artifact = compiler - .compile_into_spirv(VERTEX_SOURCE, shaderc::ShaderKind::Vertex, "vertex.vert", "main", None) + .compile_into_spirv(VERTEX_SOURCE, shaderc::ShaderKind::Vertex, "vertex.vert", ENTRY_NAME, None) .map_err(|e| error::CreationError::ShaderCError (e))?; let fragment_compile_artifact = compiler - .compile_into_spirv(FRAGMENT_SOURCE, shaderc::ShaderKind::Fragment, "fragment.frag", "main", None) + .compile_into_spirv(FRAGMENT_SOURCE, shaderc::ShaderKind::Fragment, "fragment.frag", ENTRY_NAME, None) .map_err(|e| error::CreationError::ShaderCError (e))?; // Make into shader module @@ -397,32 +376,32 @@ impl<'a> RenderingContext<'a> { .create_shader_module(fragment_compile_artifact.as_binary()) .map_err(|e| error::CreationError::ShaderModuleFailed (e))?) } - }; - - // 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() - } - ); - - // Shader set - let shaders = GraphicsShaderSet { - vertex: vs_entry, - fragment: Some(fs_entry), - hull: None, - domain: None, - geometry: None - }; - - // Vertex buffers + }; + + // 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() + } + ); + + // Shader set + let shaders = GraphicsShaderSet { + vertex: vs_entry, + fragment: Some(fs_entry), + hull: None, + domain: None, + geometry: None + }; + + // Vertex buffers let vertex_buffers: Vec<VertexBufferDesc> = vec![VertexBufferDesc { binding: 0, stride: (size_of::<f32>() * 5) as u32, @@ -445,17 +424,18 @@ impl<'a> RenderingContext<'a> { } }]; - // Rasterizer - let rasterizer = Rasterizer { - polygon_mode: PolygonMode::Fill, - cull_face: Face::NONE, - front_face: FrontFace::Clockwise, - depth_clamping: false, - depth_bias: None, - conservative: true - }; - - // Depth stencil + // Rasterizer + let rasterizer = Rasterizer { + polygon_mode: PolygonMode::Fill, + cull_face: Face::NONE, + front_face: FrontFace::Clockwise, + depth_clamping: false, + depth_bias: None, + conservative: true, + line_width: hal::pso::State::Static(1.0) + }; + + // Depth stencil let depth_stencil = DepthStencilDesc { depth: None, depth_bounds: false, @@ -463,19 +443,19 @@ impl<'a> RenderingContext<'a> { }; // Descriptor set layout - let set_layout = unsafe { - device.create_descriptor_set_layout( - &[], - &[], - ) - }.map_err(|_| error::CreationError::OutOfMemoryError)?; - - // Pipeline layout - let layout = unsafe { - device.create_pipeline_layout(std::iter::once(&set_layout), &[]) + let set_layout = unsafe { + device.create_descriptor_set_layout( + &[], + &[], + ) + }.map_err(|_| error::CreationError::OutOfMemoryError)?; + + // Pipeline layout + let layout = unsafe { + device.create_pipeline_layout(std::iter::once(&set_layout), &[]) }.map_err(|_| error::CreationError::OutOfMemoryError)?; - // Colour blending + // Colour blending let blender = { let blend_state = BlendState { color: BlendOp::Add { @@ -508,184 +488,211 @@ impl<'a> RenderingContext<'a> { // Input assembler let input_assembler = InputAssemblerDesc::new(Primitive::TriangleList); - // Pipeline description - let pipeline_desc = GraphicsPipelineDesc { - shaders, - rasterizer, - vertex_buffers, - blender, - depth_stencil, - multisampling: None, - baked_states, - layout: &layout, - subpass: *subpass, - flags: pso::PipelineCreationFlags::empty(), - parent: pso::BasePipeline::None, - input_assembler, - attributes - }; - - // Pipeline - let pipeline = unsafe { - device.create_graphics_pipeline(&pipeline_desc, None) - }.map_err(|e| error::CreationError::PipelineError (e))?; - - Ok((set_layout, layout, pipeline)) + // Pipeline description + let pipeline_desc = GraphicsPipelineDesc { + shaders, + rasterizer, + vertex_buffers, + blender, + depth_stencil, + multisampling: None, + baked_states, + layout: &layout, + subpass: *subpass, + flags: PipelineCreationFlags::empty(), + parent: BasePipeline::None, + input_assembler, + attributes + }; + + // Pipeline + let pipeline = unsafe { + device.create_graphics_pipeline(&pipeline_desc, None) + }.map_err(|e| error::CreationError::PipelineError (e))?; + + Ok((set_layout, layout, pipeline)) } - /// Draw a frame that's just cleared to the color specified. - pub fn draw_clear(&mut self, color: [f32; 4]) -> Result<(), FrameError> { - let get_image = &self.get_image[self.current_frame]; - let render_complete = &self.render_complete[self.current_frame]; - - // Advance the frame _before_ we start using the `?` operator - self.current_frame = (self.current_frame + 1) % self.frames_in_flight; - - // Get the image - let (image_index, _) = unsafe { - self - .swapchain - .acquire_image(core::u64::MAX, Some(get_image), None) - .map_err(|e| FrameError::AcquireError (e))? - }; - let image_index = image_index as usize; - - // Make sure whatever was last using this has finished - let present_complete = &self.present_complete[image_index]; - unsafe { - self.device - .wait_for_fence(present_complete, core::u64::MAX) - .map_err(|_| FrameError::SyncObjectError)?; - self.device - .reset_fence(present_complete) - .map_err(|_| FrameError::SyncObjectError)?; - }; - - // Record commands - unsafe { - let buffer = &mut self.cmd_buffers[image_index]; - let clear_values = [command::ClearValue::Color(command::ClearColor::Sfloat(color))]; - - buffer.begin(false); - buffer.begin_render_pass_inline( - &self.renderpass, - &self.framebuffers[image_index], - self.viewport.rect, - clear_values.iter(), - ); - buffer.finish(); - }; - - // Make submission object - let command_buffers = &self.cmd_buffers[image_index..=image_index]; - let wait_semaphores: ArrayVec<[_; 1]> = [(get_image, pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT)].into(); - let signal_semaphores: ArrayVec<[_; 1]> = [render_complete].into(); - - let present_wait_semaphores: ArrayVec<[_; 1]> = [render_complete].into(); - - let submission = Submission { - command_buffers, - wait_semaphores, - signal_semaphores, - }; - - // Submit it - let command_queue = &mut self.queue_group.queues[0]; - unsafe { - command_queue.submit(submission, Some(present_complete)); - self.swapchain - .present(command_queue, image_index as u32, present_wait_semaphores) - .map_err(|_| FrameError::PresentError)? - }; - - Ok(()) + /// Draw a frame that's just cleared to the color specified. + pub fn draw_clear(&mut self, color: [f32; 4]) -> Result<(), error::FrameError> { + let get_image = &self.get_image[self.current_frame]; + let render_complete = &self.render_complete[self.current_frame]; + + // Advance the frame _before_ we start using the `?` operator + self.current_frame = (self.current_frame + 1) % self.frames_in_flight; + + // Get the image + let (image_index, _) = unsafe { + self + .swapchain + .acquire_image(core::u64::MAX, Some(get_image), None) + .map_err(|e| error::FrameError::AcquireError (e))? + }; + let image_index = image_index as usize; + + // Make sure whatever was last using this has finished + let present_complete = &self.present_complete[image_index]; + unsafe { + self.device + .wait_for_fence(present_complete, core::u64::MAX) + .map_err(|_| error::FrameError::SyncObjectError)?; + self.device + .reset_fence(present_complete) + .map_err(|_| error::FrameError::SyncObjectError)?; + }; + + // Record commands + unsafe { + use hal::command::{ClearValue, ClearColor, SubpassContents, CommandBufferFlags}; + + let buffer = &mut self.cmd_buffers[image_index]; + let clear_values = [ClearValue { + color: ClearColor { + float32: color + } + }]; + + buffer.begin_primary(CommandBufferFlags::EMPTY); + buffer.begin_render_pass( + &self.renderpass, + &self.framebuffers[image_index], + self.viewport.rect, + clear_values.iter(), + SubpassContents::Inline + ); + buffer.end_render_pass(); + buffer.finish(); + }; + + // Make submission object + let command_buffers = &self.cmd_buffers[image_index..=image_index]; + let wait_semaphores: ArrayVec<[_; 1]> = [(get_image, hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT)].into(); + let signal_semaphores: ArrayVec<[_; 1]> = [render_complete].into(); + + let present_wait_semaphores: ArrayVec<[_; 1]> = [render_complete].into(); + + let submission = Submission { + command_buffers, + wait_semaphores, + signal_semaphores, + }; + + // Submit it + let command_queue = &mut self.queue_group.queues[0]; + unsafe { + command_queue.submit(submission, Some(present_complete)); + self.swapchain + .present(command_queue, image_index as u32, present_wait_semaphores) + .map_err(|_| error::FrameError::PresentError)? + }; + + Ok(()) } pub fn draw_vertices(&mut self) -> Result<(), &'static str> { - let get_image = &self.get_image[self.current_frame]; - let render_complete = &self.render_complete[self.current_frame]; - - // Advance the frame _before_ we start using the `?` operator - self.current_frame = (self.current_frame + 1) % self.frames_in_flight; - - // Get the image - let (image_index, _) = unsafe { - self - .swapchain - .acquire_image(core::u64::MAX, Some(get_image), None) - .map_err(|_| "FrameError::AcquireError")? - }; - let image_index = image_index as usize; - - // Make sure whatever was last using this has finished - let present_complete = &self.present_complete[image_index]; - unsafe { - self.device - .wait_for_fence(present_complete, core::u64::MAX) - .map_err(|_| "FrameError::SyncObjectError")?; - self.device - .reset_fence(present_complete) - .map_err(|_| "FrameError::SyncObjectError")?; - }; - - // Record commands - unsafe { - let buffer = &mut self.cmd_buffers[image_index]; - let clear_values = [command::ClearValue::Color(command::ClearColor::Sfloat([0.0, 0.0, 0.0, 1.0]))]; - - buffer.begin(false); - { - let mut encoder = buffer.begin_render_pass_inline( + let get_image = &self.get_image[self.current_frame]; + let render_complete = &self.render_complete[self.current_frame]; + + // Advance the frame _before_ we start using the `?` operator + self.current_frame = (self.current_frame + 1) % self.frames_in_flight; + + // Get the image + let (image_index, _) = unsafe { + self + .swapchain + .acquire_image(core::u64::MAX, Some(get_image), None) + .map_err(|_| "FrameError::AcquireError")? + }; + let image_index = image_index as usize; + + // Make sure whatever was last using this has finished + let present_complete = &self.present_complete[image_index]; + unsafe { + self.device + .wait_for_fence(present_complete, core::u64::MAX) + .map_err(|_| "FrameError::SyncObjectError")?; + self.device + .reset_fence(present_complete) + .map_err(|_| "FrameError::SyncObjectError")?; + }; + + // Record commands + unsafe { + use hal::buffer::{IndexBufferView, SubRange}; + use hal::command::{SubpassContents, CommandBufferFlags, ClearValue, ClearColor}; + + let buffer = &mut self.cmd_buffers[image_index]; + let clear_values = [ClearValue { + color: ClearColor { + float32: [0.0, 0.0, 0.0, 1.0] + } + }]; + + // Commit from staging buffers + let (vbufs, ibuf) = { + let vbufref: &<back::Backend as hal::Backend>::Buffer = self.vert_buffer.commit( + &self.device, + &mut self.queue_group.queues[0], + &mut self.cmd_pool + ); + + let vbufs: ArrayVec<[_; 1]> = [(vbufref, SubRange::WHOLE)].into(); + let ibuf = self.index_buffer.commit( + &self.device, + &mut self.queue_group.queues[0], + &mut self.cmd_pool + ); + + (vbufs, ibuf) + }; + + buffer.begin_primary(CommandBufferFlags::EMPTY); + { + buffer.begin_render_pass( &self.renderpass, &self.framebuffers[image_index], self.viewport.rect, clear_values.iter(), + SubpassContents::Inline ); - encoder.bind_graphics_pipeline(&self.pipeline); - - // Here we must force the Deref impl of ManuallyDrop to play nice. - let buffer_ref: &<back::Backend as hal::Backend>::Buffer = &self.map_verts.buffer; - let buffers: ArrayVec<[_; 1]> = [(buffer_ref, 0)].into(); + buffer.bind_graphics_pipeline(&self.pipeline); + buffer.end_render_pass(); + buffer.bind_vertex_buffers(0, vbufs); - encoder.bind_vertex_buffers(0, buffers); + buffer.bind_index_buffer(IndexBufferView { + buffer: ibuf, + range: SubRange::WHOLE, + index_type: hal::IndexType::U16 + }); - trace!("Requesting draw of {:?} instances ({:?} verts)", self.map_verts.active_instances, self.map_verts.active_verts); - encoder.draw(self.map_verts.active_verts.clone(), self.map_verts.active_instances.clone()); + buffer.draw_indexed(0..6, 0, 0..1); } - buffer.finish(); - }; - - // Make submission object - let command_buffers = &self.cmd_buffers[image_index..=image_index]; - let wait_semaphores: ArrayVec<[_; 1]> = [(get_image, pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT)].into(); - let signal_semaphores: ArrayVec<[_; 1]> = [render_complete].into(); - - let present_wait_semaphores: ArrayVec<[_; 1]> = [render_complete].into(); - - let submission = Submission { - command_buffers, - wait_semaphores, - signal_semaphores, - }; - - // Submit it - let command_queue = &mut self.queue_group.queues[0]; - unsafe { - command_queue.submit(submission, Some(present_complete)); - self.swapchain - .present(command_queue, image_index as u32, present_wait_semaphores) - .map_err(|_| "FrameError::PresentError")? - }; - - Ok(()) - } + buffer.finish(); + }; + + // Make submission object + let command_buffers = &self.cmd_buffers[image_index..=image_index]; + let wait_semaphores: ArrayVec<[_; 1]> = [(get_image, hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT)].into(); + let signal_semaphores: ArrayVec<[_; 1]> = [render_complete].into(); + + let present_wait_semaphores: ArrayVec<[_; 1]> = [render_complete].into(); - pub fn add_map_vert(&mut self, tri: Tri2) -> Result<(), ()> { - // get around the borrow checker + let submission = Submission { + command_buffers, + wait_semaphores, + signal_semaphores, + }; + + // Submit it + let command_queue = &mut self.queue_group.queues[0]; unsafe { - let ctx: *mut Self = &mut *self; - self.map_verts.add(tri, ctx.as_mut().unwrap()) - } + command_queue.submit(submission, Some(present_complete)); + self.swapchain + .present(command_queue, image_index as u32, present_wait_semaphores) + .map_err(|_| "FrameError::PresentError")? + }; + + Ok(()) } } @@ -695,36 +702,45 @@ impl<'a> core::ops::Drop for RenderingContext<'a> { self.device.wait_idle().unwrap(); unsafe { - for fence in self.present_complete.drain(..) { - self.device.destroy_fence(fence) - } - for semaphore in self.render_complete.drain(..) { - self.device.destroy_semaphore(semaphore) - } - for semaphore in self.get_image.drain(..) { - self.device.destroy_semaphore(semaphore) - } - for framebuffer in self.framebuffers.drain(..) { - self.device.destroy_framebuffer(framebuffer); - } - for image_view in self.imageviews.drain(..) { - self.device.destroy_image_view(image_view); - } - - // self.map_verts.deactivate(self); - - use core::ptr::read; - for cmd_pool in self.cmd_pools.drain(..) { - self.device.destroy_command_pool( - ManuallyDrop::into_inner(cmd_pool), - ); - } - self.device - .destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass))); - self.device - .destroy_swapchain(ManuallyDrop::into_inner(read(&self.swapchain))); - - ManuallyDrop::drop(&mut self.device); + for fence in self.present_complete.drain(..) { + self.device.destroy_fence(fence) + } + for semaphore in self.render_complete.drain(..) { + self.device.destroy_semaphore(semaphore) + } + for semaphore in self.get_image.drain(..) { + self.device.destroy_semaphore(semaphore) + } + for framebuffer in self.framebuffers.drain(..) { + self.device.destroy_framebuffer(framebuffer); + } + for image_view in self.imageviews.drain(..) { + self.device.destroy_image_view(image_view); + } + + use core::ptr::read; + ManuallyDrop::into_inner(read(&self.vert_buffer)).deactivate(&mut self.device); + ManuallyDrop::into_inner(read(&self.index_buffer)).deactivate(&mut self.device); + + self.device.destroy_command_pool( + ManuallyDrop::into_inner(read(&self.cmd_pool)), + ); + + self.device + .destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass))); + self.device + .destroy_swapchain(ManuallyDrop::into_inner(read(&self.swapchain))); + + self.device + .destroy_descriptor_set_layout(ManuallyDrop::into_inner(read(&self.descriptor_set_layouts))); + + self.device + .destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout))); + + self.instance + .destroy_surface(ManuallyDrop::into_inner(read(&self.surface))); + + ManuallyDrop::drop(&mut self.device); } } }
\ No newline at end of file diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs index c506f7a..1b6db2a 100644 --- a/stockton-render/src/draw/mod.rs +++ b/stockton-render/src/draw/mod.rs @@ -19,4 +19,4 @@ mod context; mod buffer; pub use self::context::RenderingContext; -pub use self::context::Tri2; +pub use self::context::UVPoint; diff --git a/stockton-render/src/error.rs b/stockton-render/src/error.rs index 485d1e7..b029975 100644 --- a/stockton-render/src/error.rs +++ b/stockton-render/src/error.rs @@ -21,7 +21,6 @@ /// - Sanity - Things that probably aren't true, likely indicating a deeper issue. /// These aren't guaranteed sanity issues, but they are weird issues. /// - Runtime - Things caused by runtime conditions, usually resource constraints. -/// You can use the associated methods to get the group of one, which may be helpful for error reporting, etc. #[derive(Debug)] pub enum CreationError { WindowError, diff --git a/stockton-render/src/lib.rs b/stockton-render/src/lib.rs index e51a582..0222933 100644 --- a/stockton-render/src/lib.rs +++ b/stockton-render/src/lib.rs @@ -13,33 +13,11 @@ // You should have received a copy of the GNU General Public License along // with this program. If not, see <http://www.gnu.org/licenses/>. -//! Renders a world to a window. -//! -//! You'll need to pick a backend using features. You should only pick one. -//! On Linux & Windows, you should use vulkan. -//! On Mac, you should use `metal`. -//! If you're targetting machines without Vulkan, OpenGL or dx11/dx12 is preferred. -//! `empty` is used for testing -#![feature(manually_drop_take)] - extern crate core; -#[cfg(feature = "dx11")] -extern crate gfx_backend_dx11 as back; - -#[cfg(feature = "dx12")] -extern crate gfx_backend_dx12 as back; - -#[cfg(feature = "gl")] -extern crate gfx_backend_gl as back; - -#[cfg(feature = "metal")] -extern crate gfx_backend_metal as back; - #[cfg(feature = "vulkan")] extern crate gfx_backend_vulkan as back; -#[macro_use] extern crate log; extern crate gfx_hal as hal; extern crate stockton_types; @@ -48,18 +26,20 @@ extern crate winit; extern crate arrayvec; -mod error; pub mod draw; +mod error; +mod types; -use error::{CreationError, FrameError}; -use draw::{RenderingContext, Tri2}; +use std::sync::{Arc, RwLock}; -use stockton_types::{World, Vector2}; +use stockton_types::World; -use std::sync::{Arc, RwLock}; +use error::{CreationError, FrameError}; +use draw::RenderingContext; +/// Renders a world to a window when you tell it to. pub struct Renderer<'a> { - world: Arc<RwLock<World<'a>>>, + _world: Arc<RwLock<World<'a>>>, pub context: RenderingContext<'a> } @@ -67,11 +47,11 @@ pub struct Renderer<'a> { impl<'a> Renderer<'a> { /// Create a new Renderer. /// This initialises all the vulkan context, etc needed. - pub fn new(world: Arc<RwLock<World<'a>>>) -> Result<Self, CreationError> { - let context = RenderingContext::new()?; + pub fn new(world: Arc<RwLock<World<'a>>>, window: &winit::window::Window) -> Result<Self, CreationError> { + let context = RenderingContext::new(window)?; Ok(Renderer { - world, context + _world: world, context }) } diff --git a/stockton-render/src/types.rs b/stockton-render/src/types.rs new file mode 100644 index 0000000..297eb69 --- /dev/null +++ b/stockton-render/src/types.rs @@ -0,0 +1,36 @@ +// Copyright (C) 2019 Oscar Shrimpton + +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. + +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. + +// You should have received a copy of the GNU General Public License along +// with this program. If not, see <http://www.gnu.org/licenses/>. + +//! Convenience module to reference types that are stored in the backend's enum + +pub type Device = <back::Backend as hal::Backend>::Device; +pub type Buffer = <back::Backend as hal::Backend>::Buffer; +pub type Memory = <back::Backend as hal::Backend>::Memory; +pub type Swapchain = <back::Backend as hal::Backend>::Swapchain; +pub type Surface = <back::Backend as hal::Backend>::Surface; +pub type Semaphore = <back::Backend as hal::Backend>::Semaphore; +pub type Fence = <back::Backend as hal::Backend>::Fence; +pub type CommandPool = <back::Backend as hal::Backend>::CommandPool; +pub type CommandBuffer = <back::Backend as hal::Backend>::CommandBuffer; +pub type CommandQueue = <back::Backend as hal::Backend>::CommandQueue; +pub type DescriptorSetLayout = <back::Backend as hal::Backend>::DescriptorSetLayout; +pub type PipelineLayout = <back::Backend as hal::Backend>::PipelineLayout; +pub type GraphicsPipeline = <back::Backend as hal::Backend>::GraphicsPipeline; +pub type ImageView = <back::Backend as hal::Backend>::ImageView; +pub type Framebuffer = <back::Backend as hal::Backend>::Framebuffer; +pub type RenderPass = <back::Backend as hal::Backend>::RenderPass; + +pub type Adapter = hal::adapter::Adapter<back::Backend>; +pub type QueueGroup = hal::queue::QueueGroup<back::Backend>;
\ No newline at end of file |