aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/render-triangles/src/main.rs106
-rw-r--r--stockton-render/Cargo.toml1
-rw-r--r--stockton-render/src/draw/context.rs95
-rw-r--r--stockton-render/src/draw/mod.rs2
-rw-r--r--stockton-render/src/draw/vertexlump.rs174
-rw-r--r--stockton-render/src/lib.rs2
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;