Skip to content

Commit

Permalink
Avoid allocation on vertex buffer binding
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Jun 28, 2018
1 parent bf3948a commit b2dc191
Show file tree
Hide file tree
Showing 13 changed files with 94 additions and 63 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ else
endif


.PHONY: all check test reftests travis-sdl2
.PHONY: all check quad test reftests travis-sdl2

all: check test

Expand All @@ -62,6 +62,9 @@ reftests-ci:
cd src/warden && cargo test --features "gl"
cd src/warden && cargo run --features "gl" -- ci #TODO: "gl-headless"

quad:
cd examples && cargo run --bin quad --features ${FEATURES_HAL}

travis-sdl2:
#TODO
#if [ -e $(SDL2_CONFIG) ]; then exit 1; fi
Expand Down
6 changes: 3 additions & 3 deletions examples/quad/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use hal::pso::{PipelineStage, ShaderStageFlags, Specialization};
use hal::queue::Submission;

use std::fs;
use std::io::Cursor;
use std::io::Read;
use std::io::{Cursor, Read};


const ENTRY_NAME: &str = "main";

Expand Down Expand Up @@ -480,7 +480,7 @@ fn main() {
cmd_buffer.set_viewports(0, &[viewport.clone()]);
cmd_buffer.set_scissors(0, &[viewport.rect]);
cmd_buffer.bind_graphics_pipeline(&pipeline);
cmd_buffer.bind_vertex_buffers(0, pso::VertexBufferSet(vec![(&vertex_buffer, 0)]));
cmd_buffer.bind_vertex_buffers(0, Some((&vertex_buffer, 0)));
cmd_buffer.bind_graphics_descriptor_sets(&pipeline_layout, 0, Some(&desc_set), &[]); //TODO

{
Expand Down
11 changes: 8 additions & 3 deletions src/backend/dx11/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,9 +866,14 @@ impl hal::command::RawCommandBuffer<Backend> for CommandBuffer {
}
}

fn bind_vertex_buffers(&mut self, first_binding: u32, vbs: pso::VertexBufferSet<Backend>) {
let (buffers, offsets): (Vec<*mut d3d11::ID3D11Buffer>, Vec<u32>) = vbs.0.iter()
.map(|(buf, offset)| (buf.internal.raw, *offset as u32))
fn bind_vertex_buffers<I, T>(&mut self, first_binding: u32, buffers: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<Buffer>,
{
let (buffers, offsets): (Vec<*mut d3d11::ID3D11Buffer>, Vec<u32>) = buffers
.into_iter()
.map(|(buf, offset)| (buf.borrow().internal.raw, offset as u32))
.unzip();

// TODO: strides
Expand Down
14 changes: 10 additions & 4 deletions src/backend/dx12/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1634,15 +1634,21 @@ impl com::RawCommandBuffer<Backend> for CommandBuffer {
}
}

fn bind_vertex_buffers(&mut self, first_binding: u32, vbs: pso::VertexBufferSet<Backend>) {
fn bind_vertex_buffers<I, T>(&mut self, first_binding: u32, buffers: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<n::Buffer>,
{
// Only cache the vertex buffer views as we don't know the stride (PSO).
assert!(first_binding as usize <= MAX_VERTEX_BUFFERS);
for (&(buffer, offset), view) in vbs.0.iter()
for (&(buffer, offset), view) in buffers
.into_iter()
.zip(self.vertex_buffer_views[first_binding as _..].iter_mut())
{
let base = unsafe { (*buffer.resource).GetGPUVirtualAddress() };
let b = buffer.borrow();
let base = unsafe { (*b.resource).GetGPUVirtualAddress() };
view.BufferLocation = base + offset as u64;
view.SizeInBytes = buffer.size_in_bytes - offset as u32;
view.SizeInBytes = b.size_in_bytes - offset as u32;
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/backend/empty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,11 @@ impl command::RawCommandBuffer<Backend> for RawCommandBuffer {
unimplemented!()
}

fn bind_vertex_buffers(&mut self, _: u32, _: pso::VertexBufferSet<Backend>) {
fn bind_vertex_buffers<I, T>(&mut self, _: u32, _: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<()>,
{
unimplemented!()
}

Expand Down
25 changes: 14 additions & 11 deletions src/backend/gl/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,17 +698,20 @@ impl command::RawCommandBuffer<Backend> for RawCommandBuffer {
self.push_cmd(Command::BindIndexBuffer(ibv.buffer.raw));
}

fn bind_vertex_buffers(&mut self, _first_binding: u32, vbs: hal::pso::VertexBufferSet<Backend>) {
if vbs.0.len() == 0 {
return
}

let needed_length = vbs.0.iter().map(|vb| vb.1).max().unwrap() + 1;

self.cache.vertex_buffers.resize(needed_length as usize, 0);

for vb in vbs.0 {
self.cache.vertex_buffers[vb.1 as usize] = vb.0.raw;
fn bind_vertex_buffers<I, T>(&mut self, first_binding: u32, buffers: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<n::Buffer>,
{
for (i, (buffer, offset)) in buffers.into_iter().enumerate() {
let index = first_binding as usize + i;
if self.cache.vertex_buffers.len() <= index {
self.cache.vertex_buffers.resize(index+1, 0);
}
self.cache.vertex_buffers[index] = buffer.borrow().raw;
if offset != 0 {
error!("Vertex buffer offset {} is not supported", offset);
}
}
}

Expand Down
27 changes: 20 additions & 7 deletions src/backend/metal/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2233,13 +2233,26 @@ impl com::RawCommandBuffer<Backend> for CommandBuffer {
});
}

fn bind_vertex_buffers(&mut self, first_binding: u32, buffer_set: pso::VertexBufferSet<Backend>) {
while self.state.vertex_buffers.len() < first_binding as usize + buffer_set.0.len() {
self.state.vertex_buffers.push(None);
}
for (i, &(buffer, offset)) in buffer_set.0.iter().enumerate() {
let buffer_ptr = BufferPtr(buffer.raw.as_ptr());
self.state.vertex_buffers[first_binding as usize + i] = Some((buffer_ptr, buffer.range.start + offset));

fn bind_vertex_buffers<I, T>(&mut self, first_binding: u32, buffers: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<native::Buffer>,
{
if self.state.vertex_buffers.len() <= first_binding as usize {
self.state.vertex_buffers.resize(first_binding as usize + 1, None);
}
for (i, (buffer, offset)) in buffers.into_iter().enumerate() {
let b = buffer.borrow();
let buffer_ptr = BufferPtr(b.raw.as_ptr());
let index = first_binding as usize + i;
let value = Some((buffer_ptr, b.range.start + offset));
if index >= self.state.vertex_buffers.len() {
debug_assert_eq!(index, self.state.vertex_buffers.len());
self.state.vertex_buffers.push(value);
} else {
self.state.vertex_buffers[index] = value;
}
}

let mask = self.state.set_vertex_buffers();
Expand Down
14 changes: 9 additions & 5 deletions src/backend/vulkan/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,11 +483,15 @@ impl com::RawCommandBuffer<Backend> for CommandBuffer {
}
}

fn bind_vertex_buffers(&mut self, first_binding: u32, vbs: pso::VertexBufferSet<Backend>) {
let buffers: SmallVec<[vk::Buffer; 16]> =
vbs.0.iter().map(|&(ref buffer, _)| buffer.raw).collect();
let offsets: SmallVec<[vk::DeviceSize; 16]> =
vbs.0.iter().map(|&(_, offset)| offset as u64).collect();
fn bind_vertex_buffers<I, T>(&mut self, first_binding: u32, buffers: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<n::Buffer>,
{
let (buffers, offsets): (SmallVec<[vk::Buffer; 16]>, SmallVec<[vk::DeviceSize; 16]>) = buffers
.into_iter()
.map(|(buffer, offset)| (buffer.borrow().raw, offset))
.unzip();

unsafe {
self.device.0.cmd_bind_vertex_buffers(
Expand Down
13 changes: 8 additions & 5 deletions src/hal/src/command/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ use std::borrow::Borrow;
use std::ops::Range;

use Backend;
use {image, pso};
use buffer::IndexBufferView;
use {buffer, image, pso};
use query::{Query, QueryControl, QueryId};
use queue::capability::{Graphics, GraphicsOrCompute, Supports};
use super::{
Expand Down Expand Up @@ -181,13 +180,17 @@ impl<'a, B: Backend, C: Supports<Graphics>, S: Shot, L: Level> CommandBuffer<'a,
}

/// Identical to the `RawCommandBuffer` method of the same name.
pub fn bind_index_buffer(&mut self, ibv: IndexBufferView<B>) {
pub fn bind_index_buffer(&mut self, ibv: buffer::IndexBufferView<B>) {
self.raw.bind_index_buffer(ibv)
}

/// Identical to the `RawCommandBuffer` method of the same name.
pub fn bind_vertex_buffers(&mut self, first_binding: u32, vbs: pso::VertexBufferSet<B>) {
self.raw.bind_vertex_buffers(first_binding, vbs)
pub fn bind_vertex_buffers<I, T>(&mut self, first_binding: u32, buffers: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<B::Buffer>,
{
self.raw.bind_vertex_buffers(first_binding, buffers)
}

/// Identical to the `RawCommandBuffer` method of the same name.
Expand Down
5 changes: 4 additions & 1 deletion src/hal/src/command/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,10 @@ pub trait RawCommandBuffer<B: Backend>: Clone + Any + Send + Sync {
///
/// Each buffer passed corresponds to the vertex input binding with the same index,
/// starting from an offset index `first_binding`.
fn bind_vertex_buffers(&mut self, first_binding: u32, pso::VertexBufferSet<B>);
fn bind_vertex_buffers<I, T>(&mut self, first_binding: u32, buffers: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<B::Buffer>;

/// Set the viewport parameters for the rasterizer.
///
Expand Down
8 changes: 6 additions & 2 deletions src/hal/src/command/render_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,12 @@ impl<'a, B: Backend> RenderSubpassCommon<'a, B> {
}

///
pub fn bind_vertex_buffers(&mut self, first_binding: u32, vbs: pso::VertexBufferSet<B>) {
self.0.bind_vertex_buffers(first_binding, vbs);
pub fn bind_vertex_buffers<I, T>(&mut self, first_binding: u32, buffers: I)
where
I: IntoIterator<Item = (T, buffer::Offset)>,
T: Borrow<B::Buffer>,
{
self.0.bind_vertex_buffers(first_binding, buffers);
}

///
Expand Down
17 changes: 1 addition & 16 deletions src/hal/src/pso/input_assembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
//! The input assembler collects raw vertex and index data.
use format;
use buffer::Offset;
use {Backend, Primitive};
use {Primitive};

/// Shader binding location.
pub type Location = u32;
Expand Down Expand Up @@ -88,17 +87,3 @@ impl InputAssemblerDesc {
}
}
}

/// A complete set of vertex buffers to be used for vertex import in PSO.
#[derive(Clone, Debug)]
pub struct VertexBufferSet<'a, B: Backend>(
/// Array of buffer handles with offsets in them
pub Vec<(&'a B::Buffer, Offset)>,
);

impl<'a, B: Backend> VertexBufferSet<'a, B> {
/// Create an empty set
pub fn new() -> Self {
VertexBufferSet(Vec::new())
}
}
6 changes: 2 additions & 4 deletions src/warden/src/gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -945,10 +945,8 @@ impl<B: hal::Backend> Scene<B, hal::General> {
.expect(&format!("Missing vertex buffer: {}", name))
.handle;
(buf, offset)
})
.collect::<Vec<_>>();
let set = pso::VertexBufferSet(buffers_raw);
encoder.bind_vertex_buffers(0, set);
});
encoder.bind_vertex_buffers(0, buffers_raw);
}
Dc::BindPipeline(ref name) => {
let pso = resources.graphics_pipelines
Expand Down

0 comments on commit b2dc191

Please sign in to comment.