diff options
-rw-r--r-- | examples/render-triangles/src/main.rs | 106 | ||||
-rw-r--r-- | stockton-render/Cargo.toml | 1 | ||||
-rw-r--r-- | stockton-render/src/draw/context.rs | 95 | ||||
-rw-r--r-- | stockton-render/src/draw/mod.rs | 2 | ||||
-rw-r--r-- | stockton-render/src/draw/vertexlump.rs | 174 | ||||
-rw-r--r-- | stockton-render/src/lib.rs | 2 |
6 files changed, 226 insertions, 154 deletions
diff --git a/examples/render-triangles/src/main.rs b/examples/render-triangles/src/main.rs index 2db2f1a..63c589b 100644 --- a/examples/render-triangles/src/main.rs +++ b/examples/render-triangles/src/main.rs @@ -15,64 +15,66 @@ //! Renders ./example.bsp -// extern crate stockton_types; -// extern crate stockton_bsp; -// extern crate stockton_render; -// extern crate winit; -// extern crate simple_logger; -// extern crate rand; +extern crate stockton_types; +extern crate stockton_bsp; +extern crate stockton_render; +extern crate winit; +extern crate simple_logger; +extern crate rand; -// use stockton_render::draw::{RenderingContext, Tri2}; -// use stockton_types::Vector2; +use stockton_render::draw::{RenderingContext, Tri2}; +use stockton_types::Vector2; -// use winit::{Event, WindowEvent, VirtualKeyCode, ElementState}; -// use rand::prelude::*; +use winit::{Event, WindowEvent, VirtualKeyCode, ElementState}; +use rand::prelude::*; fn main() { - // simple_logger::init().unwrap(); + simple_logger::init().unwrap(); - // // Create the renderer. - // let mut ctx = RenderingContext::new().unwrap(); - // let mut rng = thread_rng(); - // let mut vertices: VertexLump<Tri2> = VertexLump::new(&mut ctx); - // let mut running = true; - // let mut vertices_dirty = false; + // Create the renderer. + let mut ctx = RenderingContext::new().unwrap(); + let mut rng = thread_rng(); + let mut running = true; + let mut add_tri = false; - // while running { - // ctx.events_loop.poll_events(|event| { - // match event { - // // TODO: Handle resize - // Event::WindowEvent { - // event: WindowEvent::KeyboardInput { input, .. }, - // .. - // } => match input.state { - // ElementState::Released => match input.virtual_keycode { - // Some(VirtualKeyCode::Escape) => running = false, - // Some(VirtualKeyCode::Space) => { - // vertices.add(Tri2 ([ - // Vector2::new( - // rng.gen_range(-1.0, 1.0), - // rng.gen_range(-1.0, 1.0), - // ), - // Vector2::new( - // rng.gen_range(-1.0, 1.0), - // rng.gen_range(-1.0, 1.0), - // ), - // Vector2::new( - // rng.gen_range(-1.0, 1.0), - // rng.gen_range(-1.0, 1.0), - // ) - // ])); - // }, - // _ => () - // }, - // _ => () - // } - // _ => () - // } - // }); + while running { + ctx.events_loop.poll_events(|event| { + match event { + // TODO: Handle resize + Event::WindowEvent { + event: WindowEvent::KeyboardInput { input, .. }, + .. + } => match input.state { + ElementState::Released => match input.virtual_keycode { + Some(VirtualKeyCode::Escape) => running = false, + Some(VirtualKeyCode::Space) => add_tri = true, + _ => () + }, + _ => () + } + _ => () + } + }); - // vertices.draw(&mut ctx).unwrap(); - // } + if add_tri { + ctx.add_map_vert(Tri2 ([ + Vector2::new( + rng.gen_range(-1.0, 1.0), + rng.gen_range(-1.0, 1.0), + ), + Vector2::new( + rng.gen_range(-1.0, 1.0), + rng.gen_range(-1.0, 1.0), + ), + Vector2::new( + rng.gen_range(-1.0, 1.0), + rng.gen_range(-1.0, 1.0), + ) + ])).unwrap(); + add_tri = false; + } + + ctx.draw_vertices().unwrap(); + } } diff --git a/stockton-render/Cargo.toml b/stockton-render/Cargo.toml index 62c4742..01b6caa 100644 --- a/stockton-render/Cargo.toml +++ b/stockton-render/Cargo.toml @@ -11,6 +11,7 @@ gfx-hal = "0.2.1" arrayvec = "0.4.10" nalgebra-glm = "0.4.0" shaderc = "0.5.0" +log = "0.4.0" [features] default = ["vulkan"] diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs index 489ddca..7786f6d 100644 --- a/stockton-render/src/draw/context.rs +++ b/stockton-render/src/draw/context.rs @@ -16,6 +16,7 @@ //! Deals with all the Vulkan/HAL details. use crate::error as error; use crate::error::{CreationError, FrameError}; +use super::VertexLump; use core::mem::{ManuallyDrop, size_of}; use std::convert::TryInto; @@ -103,9 +104,7 @@ pub struct RenderingContext { cmd_buffers: Vec<command::CommandBuffer<Backend, Graphics, command::MultiShot>>, queue_group: QueueGroup<Backend, Graphics>, - buffer: ManuallyDrop<<Backend as hal::Backend>::Buffer>, - memory: ManuallyDrop<<Backend as hal::Backend>::Memory>, - requirements: memory::Requirements, + map_verts: VertexLump<Tri2, [f32; 15]>, descriptor_set_layouts: <Backend as hal::Backend>::DescriptorSetLayout, pipeline_layout: ManuallyDrop<<Backend as hal::Backend>::PipelineLayout>, @@ -264,8 +263,7 @@ impl RenderingContext { }; // Vertex buffer - // TODO: Proper sizing / resizing - let (buffer, requirements, memory) = Self::allocate_vertex_buffer(VERTEX_BUFFER_INITIAL_BATCHES, &mut device, &adapter)?; + let map_verts = VertexLump::new(&mut device, &adapter)?; // Command Pools, Buffers, imageviews, framebuffers & Sync objects let frames_in_flight = backbuffer.len(); @@ -338,9 +336,7 @@ impl RenderingContext { pipeline_layout: ManuallyDrop::new(pipeline_layout), pipeline: ManuallyDrop::new(pipeline), - buffer: ManuallyDrop::new(buffer), - memory: ManuallyDrop::new(memory), - requirements, + map_verts, adapter }) @@ -512,35 +508,6 @@ impl RenderingContext { Ok((set_layout, layout, pipeline)) } - pub fn allocate_vertex_buffer(batches: u64, device: &mut <Backend as hal::Backend>::Device, adapter: &adapter::Adapter<Backend>) - -> Result<(<Backend as hal::Backend>::Buffer, - memory::Requirements, - <Backend as hal::Backend>::Memory), CreationError> { - let mut buffer = unsafe { device - .create_buffer(batches * VERTEX_BUFFER_BATCH_SIZE * TRI2_SIZE_BYTES as u64, buffer::Usage::VERTEX) } - .map_err(|e| CreationError::BufferError (e))?; - - let requirements = unsafe { device.get_buffer_requirements(&buffer) }; - let memory_type_id = adapter.physical_device - .memory_properties().memory_types - .iter().enumerate() - .find(|&(id, memory_type)| { - requirements.type_mask & (1 << id) != 0 && memory_type.properties.contains(memory::Properties::CPU_VISIBLE) - }) - .map(|(id, _)| MemoryTypeId(id)) - .ok_or(CreationError::BufferNoMemory)?; - - let memory = unsafe {device - .allocate_memory(memory_type_id, requirements.size) } - .map_err(|_| CreationError::OutOfMemoryError)?; - - unsafe { device - .bind_buffer_memory(&memory, 0, &mut buffer) } - .map_err(|_| CreationError::BufferNoMemory)?; - - Ok((buffer, requirements, memory)) - } - /// 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]; @@ -609,44 +576,6 @@ impl RenderingContext { Ok(()) } - pub fn populate_vertices(&mut self, tris: &[Tri2]) -> Result<(), &'static str> { - // Ensure buffer is big enough - if tris.len() > (self.requirements.size as usize / TRI2_SIZE_BYTES) { - // Reallocate buffer - // Destroy old one - unsafe { self.device.free_memory(ManuallyDrop::take(&mut self.memory)) }; - unsafe { self.device.destroy_buffer(ManuallyDrop::take(&mut self.buffer)) }; - - // Make new one - let batches = (tris.len() as u64 / VERTEX_BUFFER_BATCH_SIZE) + 1; - - let (buffer, requirements, memory) = Self::allocate_vertex_buffer(batches, &mut self.device, &self.adapter) - .map_err(|_| "Couldn't re-allocate vertex buffer")?; - self.buffer = ManuallyDrop::new(buffer); - self.requirements = requirements; - self.memory = ManuallyDrop::new(memory); - } - - // Write triangles to the vertex buffer - unsafe { - let mut data_target: mapping::Writer<_, f32> = self.device - .acquire_mapping_writer(&self.memory, 0..self.requirements.size) - .map_err(|_| "Failed to acquire a memory writer!")?; - - for (i,tri) in tris.into_iter().enumerate() { - let points: [f32; 15] = (*tri).into(); - data_target[i * TRI2_SIZE_F32..(i * TRI2_SIZE_F32) + TRI2_SIZE_F32].copy_from_slice(&points); - } - - self - .device - .release_mapping_writer(data_target) - .map_err(|_| "Couldn't release the mapping writer!")?; - }; - - 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]; @@ -690,11 +619,13 @@ impl RenderingContext { encoder.bind_graphics_pipeline(&self.pipeline); // Here we must force the Deref impl of ManuallyDrop to play nice. - let buffer_ref: &<Backend as hal::Backend>::Buffer = &self.buffer; + let buffer_ref: &<Backend as hal::Backend>::Buffer = &self.map_verts.buffer; let buffers: ArrayVec<[_; 1]> = [(buffer_ref, 0)].into(); encoder.bind_vertex_buffers(0, buffers); - encoder.draw(0..self.requirements.size as u32, 0..(self.requirements.size / TRI2_SIZE_BYTES as u64) as u32); + + 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.finish(); }; @@ -723,6 +654,14 @@ impl RenderingContext { Ok(()) } + + pub fn add_map_vert(&mut self, tri: Tri2) -> Result<(), ()> { + // get around the borrow checker + unsafe { + let ctx: *mut Self = &mut *self; + self.map_verts.add(tri, ctx.as_mut().unwrap()) + } + } } #[cfg(feature = "gl")] @@ -750,6 +689,8 @@ impl core::ops::Drop for RenderingContext { 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( diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs index 53e2f40..53e9e50 100644 --- a/stockton-render/src/draw/mod.rs +++ b/stockton-render/src/draw/mod.rs @@ -20,4 +20,4 @@ mod vertexlump; pub use context::RenderingContext; pub use context::Tri2; -pub use vertexlump::VertexLump;
\ No newline at end of file +pub(crate) use vertexlump::VertexLump;
\ No newline at end of file diff --git a/stockton-render/src/draw/vertexlump.rs b/stockton-render/src/draw/vertexlump.rs index 534b3d9..e5a0700 100644 --- a/stockton-render/src/draw/vertexlump.rs +++ b/stockton-render/src/draw/vertexlump.rs @@ -14,42 +14,53 @@ // with this program. If not, see <http://www.gnu.org/licenses/>. use std::marker::PhantomData; -use core::mem::{size_of}; +use std::ops::{Index, IndexMut, Range}; +use std::convert::TryInto; +use core::mem::{ManuallyDrop, size_of}; use hal::memory::{Pod, Properties, Requirements}; use hal::buffer::Usage; use hal::adapter::MemoryTypeId; -use hal::{Device, PhysicalDevice, mapping}; +use hal::{VertexCount, InstanceCount, Adapter, Device, PhysicalDevice, mapping}; use back::Backend; use crate::error::CreationError; use super::RenderingContext; -pub struct VertexLump<T: Into<X>, X: Pod> { - buffer: <Backend as hal::Backend>::Buffer, - memory: <Backend as hal::Backend>::Memory, +pub(crate) struct VertexLump<T: Into<X>, X: Pod> { + pub (crate) buffer: ManuallyDrop<<Backend as hal::Backend>::Buffer>, + memory: ManuallyDrop<<Backend as hal::Backend>::Memory>, requirements: Requirements, unit_size_bytes: u64, + unit_size_verts: u64, batch_size: u64, + num_batches: usize, + + + /// An instance is active if it has been assigned to + pub active_instances: Range<InstanceCount>, + pub active_verts: Range<VertexCount>, + active: bool, _t: PhantomData<T>, - _x: PhantomData<X>, + _x: PhantomData<X> } const BATCH_SIZE: u64 = 3; impl<T: Into<X>, X: Pod> VertexLump<T, X> { - pub(crate) fn new(ctx: &mut RenderingContext) -> Result<VertexLump<T, X>, CreationError> { - let unit_size_bytes = size_of::<X>() as u64; + pub fn new(device: &mut <Backend as hal::Backend>::Device, adapter: &Adapter<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; - let mut buffer = unsafe { ctx.device + let mut buffer = unsafe { device .create_buffer(BATCH_SIZE * unit_size_bytes, Usage::VERTEX) } .map_err(|e| CreationError::BufferError (e))?; - let requirements = unsafe { ctx.device.get_buffer_requirements(&buffer) }; - let memory_type_id = ctx.adapter.physical_device + let requirements = unsafe { device.get_buffer_requirements(&buffer) }; + let memory_type_id = adapter.physical_device .memory_properties().memory_types .iter().enumerate() .find(|&(id, memory_type)| { @@ -58,18 +69,23 @@ impl<T: Into<X>, X: Pod> VertexLump<T, X> { .map(|(id, _)| MemoryTypeId(id)) .ok_or(CreationError::BufferNoMemory)?; - let memory = unsafe {ctx.device + let memory = unsafe {device .allocate_memory(memory_type_id, requirements.size) } .map_err(|_| CreationError::OutOfMemoryError)?; - unsafe { ctx.device + unsafe { device .bind_buffer_memory(&memory, 0, &mut buffer) } .map_err(|_| CreationError::BufferNoMemory)?; Ok(VertexLump { - buffer, memory, requirements, - + buffer: ManuallyDrop::new(buffer), + memory: ManuallyDrop::new(memory), + requirements, + active_verts: 0..0, + active_instances: 0..0, + num_batches: 1, unit_size_bytes, + unit_size_verts, batch_size: BATCH_SIZE, // TODO active: true, _t: PhantomData, @@ -77,36 +93,146 @@ impl<T: Into<X>, X: Pod> VertexLump<T, X> { }) } - pub(crate) fn writer<'a>(&'a self, ctx: &'a mut RenderingContext) -> Result<VertexWriter<'a, X>, ()> { + pub fn set_active_instances(&mut self, range: Range<InstanceCount>) { + let count: u64 = (range.end - range.start).into(); + let size_verts: u32 = (count * self.unit_size_verts).try_into().unwrap(); + self.active_verts = range.start * size_verts..range.end * size_verts; + self.active_instances = range; + } + + pub fn add(&mut self, tri: T, ctx: &mut RenderingContext) -> Result<(), ()> { + + // figure out where to put it + let idx: usize = (self.active_instances.end).try_into().unwrap(); + let batch_size: usize = self.batch_size.try_into().unwrap(); + let max_size: usize = self.num_batches * batch_size; + + // make sure correct size + if idx >= max_size { + self.num_batches += 1; + + debug!("Reallocating Vertex buffer to {} batches ({} instances)", self.num_batches, self.num_batches as u64 * self.batch_size); + // get new buffer + let (new_buffer, new_requirements, new_memory) = { + let mut buffer = ManuallyDrop::new(unsafe { ctx.device + .create_buffer(self.batch_size * self.unit_size_bytes * self.num_batches as u64, Usage::VERTEX) } + .map_err(|_| ())? + ); + let requirements = unsafe { ctx.device.get_buffer_requirements(&buffer) }; + + let memory_type_id = ctx.adapter.physical_device + .memory_properties().memory_types + .iter().enumerate() + .find(|&(id, memory_type)| { + requirements.type_mask & (1 << id) != 0 && memory_type.properties.contains(Properties::CPU_VISIBLE) + }) + .map(|(id, _)| MemoryTypeId(id)) + .ok_or(())?; + + let memory = ManuallyDrop::new(unsafe { ctx.device + .allocate_memory(memory_type_id, requirements.size) } + .map_err(|_| ())?); + + unsafe { ctx.device + .bind_buffer_memory(&memory, 0, &mut buffer) } + .map_err(|_| ())?; + + (buffer, requirements, memory) + }; + + // copy vertices + unsafe { + let copy_range = 0..self.requirements.size; + + trace!("Copying {:?} from old buffer to new buffer", copy_range); + + let reader = ctx.device.acquire_mapping_reader::<u8>(&self.memory, copy_range.clone()) + .map_err(|_| ())?; + let mut writer = ctx.device.acquire_mapping_writer::<u8>(&new_memory, copy_range.clone()) + .map_err(|_| ())?; + + let copy_range: Range<usize> = 0..self.requirements.size.try_into().unwrap(); + writer[copy_range.clone()].copy_from_slice(&reader[copy_range.clone()]); + + ctx.device.release_mapping_reader(reader); + ctx.device.release_mapping_writer(writer).map_err(|_| ())?; + }; + + // destroy old buffer + self.deactivate(ctx); + + // use new one + self.buffer = new_buffer; + self.requirements = new_requirements; + self.memory = new_memory; + self.active = true; + + } + + { + // acquire writer + let mut writer = self.writer(ctx)?; + + // write to it + writer[idx] = tri.into(); + } + + // activate new triangle + let new_range = self.active_instances.start..self.active_instances.end + 1; + self.set_active_instances(new_range); + + Ok(()) + } + + pub(crate) fn writer<'a>(&'a mut self, ctx: &'a mut RenderingContext) -> Result<VertexWriter<'a, X>, ()> { let mapping_writer = unsafe { ctx.device .acquire_mapping_writer(&self.memory, 0..self.requirements.size) .map_err(|_| ())? }; - + Ok(VertexWriter { - mapping_writer, + mapping_writer: ManuallyDrop::new(mapping_writer), ctx }) } + + 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; + } } -// TODO pub struct VertexWriter<'a, X: Pod> { - mapping_writer: mapping::Writer<'a, Backend, X>, + mapping_writer: ManuallyDrop<mapping::Writer<'a, Backend, X>>, ctx: &'a mut RenderingContext } -impl<'a, X: Pod> IndexMut<usize> for - impl<'a, X: Pod> Drop for VertexWriter<'a, X> { fn drop(&mut self) { - // TODO + unsafe { + self.ctx.device.release_mapping_writer(ManuallyDrop::take(&mut self.mapping_writer)) + }.unwrap(); } } +impl<'a, X: Pod> Index<usize> for VertexWriter<'a, X> { + type Output = X; + + fn index(&self, index: usize) -> &Self::Output { + &self.mapping_writer[index] + } +} + +impl<'a, X: Pod> IndexMut<usize> for VertexWriter<'a, X> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.mapping_writer[index] + } +} + impl<T: Into<X>, X: Pod> Drop for VertexLump<T, X> { fn drop(&mut self) { - if !self.active { + if self.active { panic!("VertexLump dropped without being deactivated"); } } diff --git a/stockton-render/src/lib.rs b/stockton-render/src/lib.rs index 0bfc8ef..7d97d97 100644 --- a/stockton-render/src/lib.rs +++ b/stockton-render/src/lib.rs @@ -37,6 +37,8 @@ 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; extern crate shaderc; |