Buffer transitions for a render pass

This commit is contained in:
Dzmitry Malyshau 2018-10-19 12:07:07 -04:00
parent f9cd55ed59
commit b27650bfcd
9 changed files with 130 additions and 67 deletions

View File

@ -1,5 +1,6 @@
use super::CommandBuffer; use super::CommandBuffer;
use {DeviceId, Stored}; use {DeviceId, Stored};
use track::{Tracker};
use hal::command::RawCommandBuffer; use hal::command::RawCommandBuffer;
use hal::pool::RawCommandPool; use hal::pool::RawCommandPool;
@ -90,6 +91,8 @@ impl<B: hal::Backend> CommandAllocator<B> {
fence, fence,
recorded_thread_id: thread_id, recorded_thread_id: thread_id,
device_id: Stored(device_id), device_id: Stored(device_id),
buffer_tracker: Tracker::new(),
texture_tracker: Tracker::new(),
} }
} }

View File

@ -13,9 +13,11 @@ use {
BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId, BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId,
}; };
use registry::{HUB, Items, Registry}; use registry::{HUB, Items, Registry};
use track::{BufferTracker, TextureTracker};
use std::thread::ThreadId; use std::thread::ThreadId;
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum LoadOp { pub enum LoadOp {
@ -76,6 +78,8 @@ pub struct CommandBuffer<B: hal::Backend> {
fence: B::Fence, fence: B::Fence,
recorded_thread_id: ThreadId, recorded_thread_id: ThreadId,
device_id: Stored<DeviceId>, device_id: Stored<DeviceId>,
buffer_tracker: BufferTracker,
texture_tracker: TextureTracker,
} }
#[repr(C)] #[repr(C)]

View File

@ -1,5 +1,6 @@
use conv;
use registry::{HUB, Items, Registry}; use registry::{HUB, Items, Registry};
use track::{Tracker}; use track::{BufferTracker, TextureTracker, Tracktion, TrackPermit};
use { use {
Stored, Stored,
CommandBufferId, RenderPassId, CommandBufferId, RenderPassId,
@ -8,13 +9,12 @@ use {
use hal; use hal;
use hal::command::RawCommandBuffer; use hal::command::RawCommandBuffer;
use std::iter;
pub struct RenderPass<B: hal::Backend> { pub struct RenderPass<B: hal::Backend> {
raw: B::CommandBuffer, raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>, cmb_id: Stored<CommandBufferId>,
tracker: Tracker, buffer_tracker: BufferTracker,
texture_tracker: TextureTracker,
} }
impl<B: hal::Backend> RenderPass<B> { impl<B: hal::Backend> RenderPass<B> {
@ -25,7 +25,8 @@ impl<B: hal::Backend> RenderPass<B> {
RenderPass { RenderPass {
raw, raw,
cmb_id: Stored(cmb_id), cmb_id: Stored(cmb_id),
tracker: Tracker::default(), buffer_tracker: BufferTracker::new(),
texture_tracker: TextureTracker::new(),
} }
} }
} }
@ -39,11 +40,34 @@ pub extern "C" fn wgpu_render_pass_end_pass(
.take(pass_id); .take(pass_id);
pass.raw.end_render_pass(); pass.raw.end_render_pass();
HUB.command_buffers let buffer_guard = HUB.buffers.lock();
.lock() //let texture_guard = HUB.textures.lock();
.get_mut(pass.cmb_id.0) let mut cmb_guard = HUB.command_buffers.lock();
.raw let cmb = cmb_guard.get_mut(pass.cmb_id.0);
.push(pass.raw); let cmb_buffers = &mut cmb.buffer_tracker;
let buffer_barriers = pass.buffer_tracker
.finish()
.into_iter()
.flat_map(|(id, new)| {
match cmb_buffers.track(id.0, new, TrackPermit::REPLACE) {
Ok(Tracktion::Init) => None,
Ok(Tracktion::Keep) => None,
Ok(Tracktion::Replace { old }) => Some(hal::memory::Barrier::Buffer {
states: conv::map_buffer_state(old) .. conv::map_buffer_state(new),
target: &buffer_guard.get(id.0).raw,
}),
Ok(Tracktion::Extend { .. }) |
Err(_) => panic!("Unable to do the resource transition for a pass"),
}
});
pass.raw.pipeline_barrier(
hal::pso::PipelineStage::TOP_OF_PIPE .. hal::pso::PipelineStage::BOTTOM_OF_PIPE,
hal::memory::Dependencies::empty(),
buffer_barriers,
);
cmb.raw.push(pass.raw);
pass.cmb_id.0 pass.cmb_id.0
} }

View File

@ -2,7 +2,8 @@ use hal;
use {Extent3d, binding_model, pipeline, resource}; use {Extent3d, binding_model, pipeline, resource};
pub(crate) fn map_buffer_usage(
pub fn map_buffer_usage(
usage: resource::BufferUsageFlags, usage: resource::BufferUsageFlags,
) -> (hal::buffer::Usage, hal::memory::Properties) { ) -> (hal::buffer::Usage, hal::memory::Properties) {
use hal::buffer::Usage as U; use hal::buffer::Usage as U;
@ -40,7 +41,7 @@ pub(crate) fn map_buffer_usage(
(hal_usage, hal_memory) (hal_usage, hal_memory)
} }
pub(crate) fn map_binding_type( pub fn map_binding_type(
binding_ty: binding_model::BindingType, binding_ty: binding_model::BindingType,
) -> hal::pso::DescriptorType { ) -> hal::pso::DescriptorType {
use binding_model::BindingType::*; use binding_model::BindingType::*;
@ -53,7 +54,7 @@ pub(crate) fn map_binding_type(
} }
} }
pub(crate) fn map_shader_stage_flags( pub fn map_shader_stage_flags(
shader_stage_flags: binding_model::ShaderStageFlags, shader_stage_flags: binding_model::ShaderStageFlags,
) -> hal::pso::ShaderStageFlags { ) -> hal::pso::ShaderStageFlags {
use binding_model::{ use binding_model::{
@ -73,7 +74,7 @@ pub(crate) fn map_shader_stage_flags(
value value
} }
pub(crate) fn map_primitive_topology( pub fn map_primitive_topology(
primitive_topology: pipeline::PrimitiveTopology, primitive_topology: pipeline::PrimitiveTopology,
) -> hal::Primitive { ) -> hal::Primitive {
use hal::Primitive as H; use hal::Primitive as H;
@ -87,7 +88,7 @@ pub(crate) fn map_primitive_topology(
} }
} }
pub(crate) fn map_blend_state_descriptor( pub fn map_blend_state_descriptor(
desc: &pipeline::BlendStateDescriptor, desc: &pipeline::BlendStateDescriptor,
) -> hal::pso::ColorBlendDesc { ) -> hal::pso::ColorBlendDesc {
let color_mask = desc.write_mask; let color_mask = desc.write_mask;
@ -164,7 +165,7 @@ fn map_blend_factor(blend_factor: pipeline::BlendFactor) -> hal::pso::Factor {
} }
} }
pub(crate) fn map_depth_stencil_state( pub fn map_depth_stencil_state(
desc: &pipeline::DepthStencilStateDescriptor, desc: &pipeline::DepthStencilStateDescriptor,
) -> hal::pso::DepthStencilDesc { ) -> hal::pso::DepthStencilDesc {
hal::pso::DepthStencilDesc { hal::pso::DepthStencilDesc {
@ -228,7 +229,7 @@ fn map_stencil_operation(stencil_operation: pipeline::StencilOperation) -> hal::
} }
} }
pub(crate) fn map_texture_format(texture_format: resource::TextureFormat) -> hal::format::Format { pub fn map_texture_format(texture_format: resource::TextureFormat) -> hal::format::Format {
use hal::format::Format as H; use hal::format::Format as H;
use resource::TextureFormat::*; use resource::TextureFormat::*;
match texture_format { match texture_format {
@ -244,7 +245,7 @@ fn checked_u32_as_u16(value: u32) -> u16 {
value as u16 value as u16
} }
pub(crate) fn map_texture_dimension_size( pub fn map_texture_dimension_size(
dimension: resource::TextureDimension, size: Extent3d dimension: resource::TextureDimension, size: Extent3d
) -> hal::image::Kind { ) -> hal::image::Kind {
use hal::image::Kind as H; use hal::image::Kind as H;
@ -260,7 +261,7 @@ pub(crate) fn map_texture_dimension_size(
} }
} }
pub(crate) fn map_texture_usage_flags( pub fn map_texture_usage(
flags: resource::TextureUsageFlags, format: hal::format::Format flags: resource::TextureUsageFlags, format: hal::format::Format
) -> hal::image::Usage { ) -> hal::image::Usage {
use hal::image::Usage as U; use hal::image::Usage as U;
@ -290,3 +291,32 @@ pub(crate) fn map_texture_usage_flags(
// TODO: HAL Transient Attachment, HAL Input Attachment // TODO: HAL Transient Attachment, HAL Input Attachment
value value
} }
pub fn map_buffer_state(
usage: resource::BufferUsageFlags,
) -> hal::buffer::State {
use hal::buffer::Access as A;
use resource::BufferUsageFlags as W;
let mut access = A::empty();
if usage.contains(W::TRANSFER_SRC) {
access |= A::TRANSFER_READ;
}
if usage.contains(W::TRANSFER_DST) {
access |= A::TRANSFER_WRITE;
}
if usage.contains(W::INDEX) {
access |= A::INDEX_BUFFER_READ;
}
if usage.contains(W::VERTEX) {
access |= A::VERTEX_BUFFER_READ;
}
if usage.contains(W::UNIFORM) {
access |= A::CONSTANT_BUFFER_READ | A::SHADER_READ;
}
if usage.contains(W::STORAGE) {
access |= A::SHADER_WRITE;
}
access
}

View File

@ -1,8 +1,7 @@
use {back, binding_model, command, conv, pipeline, resource}; use {back, binding_model, command, conv, pipeline, resource};
use registry::{HUB, Items, Registry}; use registry::{HUB, Items, Registry};
use track::{Tracker, UsePermit}; use track::{BufferTracker, TextureTracker, TrackPermit};
use { use {
Stored,
AttachmentStateId, BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId, AttachmentStateId, BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId,
DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId, TextureId, DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId, TextureId,
}; };
@ -10,9 +9,10 @@ use {
use hal::command::RawCommandBuffer; use hal::command::RawCommandBuffer;
use hal::queue::RawCommandQueue; use hal::queue::RawCommandQueue;
use hal::{self, Device as _Device}; use hal::{self, Device as _Device};
use rendy_memory::{allocator, Config, Heaps};
use std::{ffi, slice}; use std::{ffi, slice};
use rendy_memory::{allocator, Config, Heaps}; use std::sync::Mutex;
pub struct Device<B: hal::Backend> { pub struct Device<B: hal::Backend> {
@ -20,7 +20,8 @@ pub struct Device<B: hal::Backend> {
queue_group: hal::QueueGroup<B, hal::General>, queue_group: hal::QueueGroup<B, hal::General>,
mem_allocator: Heaps<B::Memory>, mem_allocator: Heaps<B::Memory>,
pub(crate) com_allocator: command::CommandAllocator<B>, pub(crate) com_allocator: command::CommandAllocator<B>,
tracker: Tracker, buffer_tracker: Mutex<BufferTracker>,
texture_tracker: Mutex<TextureTracker>,
mem_props: hal::MemoryProperties, mem_props: hal::MemoryProperties,
} }
@ -56,7 +57,8 @@ impl<B: hal::Backend> Device<B> {
mem_allocator, mem_allocator,
com_allocator: command::CommandAllocator::new(queue_group.family()), com_allocator: command::CommandAllocator::new(queue_group.family()),
queue_group, queue_group,
tracker: Tracker::default(), buffer_tracker: Mutex::new(BufferTracker::new()),
texture_tracker: Mutex::new(TextureTracker::new()),
mem_props, mem_props,
} }
} }
@ -73,7 +75,7 @@ pub extern "C" fn wgpu_device_create_texture(
) -> TextureId { ) -> TextureId {
let kind = conv::map_texture_dimension_size(desc.dimension, desc.size); let kind = conv::map_texture_dimension_size(desc.dimension, desc.size);
let format = conv::map_texture_format(desc.format); let format = conv::map_texture_format(desc.format);
let usage = conv::map_texture_usage_flags(desc.usage, format); let usage = conv::map_texture_usage(desc.usage, format);
let device_guard = HUB.devices.lock(); let device_guard = HUB.devices.lock();
let device = &device_guard.get(device_id); let device = &device_guard.get(device_id);
let image_unbound = device let image_unbound = device
@ -111,7 +113,10 @@ pub extern "C" fn wgpu_device_create_texture(
.register(resource::Texture { .register(resource::Texture {
raw: bound_image, raw: bound_image,
}); });
device.tracker.use_texture(Stored(id), resource::TextureUsageFlags::empty(), UsePermit::empty()) device.texture_tracker
.lock()
.unwrap()
.track(id, resource::TextureUsageFlags::empty(), TrackPermit::empty())
.expect("Resource somehow is already registered"); .expect("Resource somehow is already registered");
id id
@ -224,7 +229,7 @@ pub extern "C" fn wgpu_device_create_command_buffer(
device_id: DeviceId, device_id: DeviceId,
_desc: &command::CommandBufferDescriptor, _desc: &command::CommandBufferDescriptor,
) -> CommandBufferId { ) -> CommandBufferId {
let mut device_guard = HUB.devices.lock(); let device_guard = HUB.devices.lock();
let device = device_guard.get(device_id); let device = device_guard.get(device_id);
let mut cmd_buf = device.com_allocator.allocate(device_id, &device.raw); let mut cmd_buf = device.com_allocator.allocate(device_id, &device.raw);

View File

@ -96,6 +96,7 @@ pub type DeviceId = Id;
type DeviceHandle = Device<B>; type DeviceHandle = Device<B>;
pub type QueueId = Id; pub type QueueId = Id;
pub type BufferId = Id; pub type BufferId = Id;
type BufferHandle = Buffer<B>;
// Resource // Resource
pub type TextureViewId = Id; pub type TextureViewId = Id;

View File

@ -13,7 +13,7 @@ use {
BlendStateHandle, CommandBufferHandle, DepthStencilStateHandle, DeviceHandle, InstanceHandle, BlendStateHandle, CommandBufferHandle, DepthStencilStateHandle, DeviceHandle, InstanceHandle,
RenderPassHandle, ComputePassHandle, RenderPassHandle, ComputePassHandle,
PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle, PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle,
TextureHandle, BufferHandle, TextureHandle,
}; };
@ -48,6 +48,7 @@ pub struct Hub {
pub(crate) compute_pipelines: ConcreteRegistry<ComputePipelineHandle>, pub(crate) compute_pipelines: ConcreteRegistry<ComputePipelineHandle>,
pub(crate) render_passes: ConcreteRegistry<RenderPassHandle>, pub(crate) render_passes: ConcreteRegistry<RenderPassHandle>,
pub(crate) compute_passes: ConcreteRegistry<ComputePassHandle>, pub(crate) compute_passes: ConcreteRegistry<ComputePassHandle>,
pub(crate) buffers: ConcreteRegistry<BufferHandle>,
pub(crate) textures: ConcreteRegistry<TextureHandle>, pub(crate) textures: ConcreteRegistry<TextureHandle>,
} }

View File

@ -25,9 +25,9 @@ pub struct BufferDescriptor {
pub usage: BufferUsageFlags, pub usage: BufferUsageFlags,
} }
pub struct Buffer<B: hal::Backend> { pub(crate) struct Buffer<B: hal::Backend> {
pub(crate) raw: B::UnboundBuffer, pub raw: B::UnboundBuffer,
pub(crate) memory_properties: hal::memory::Properties, pub memory_properties: hal::memory::Properties,
// TODO: mapping, unmap() // TODO: mapping, unmap()
} }
@ -75,8 +75,8 @@ pub struct TextureDescriptor {
pub usage: TextureUsageFlags, pub usage: TextureUsageFlags,
} }
pub struct Texture<B: hal::Backend> { pub(crate) struct Texture<B: hal::Backend> {
pub(crate) raw: B::Image, pub raw: B::Image,
} }
#[repr(C)] #[repr(C)]

View File

@ -4,11 +4,10 @@ use resource::{BufferUsageFlags, TextureUsageFlags};
use std::collections::hash_map::{Entry, HashMap}; use std::collections::hash_map::{Entry, HashMap};
use std::hash::Hash; use std::hash::Hash;
use std::ops::BitOr; use std::ops::BitOr;
use std::sync::Mutex;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum UseAction<T> { pub enum Tracktion<T> {
Init, Init,
Keep, Keep,
Extend { old: T }, Extend { old: T },
@ -16,14 +15,14 @@ pub enum UseAction<T> {
} }
bitflags! { bitflags! {
pub struct UsePermit: u32 { pub struct TrackPermit: u32 {
const EXTEND = 1; const EXTEND = 1;
const REPLACE = 2; const REPLACE = 2;
} }
} }
trait GenericUsage { pub trait GenericUsage {
fn is_exclusive(&self) -> bool; fn is_exclusive(&self) -> bool;
} }
impl GenericUsage for BufferUsageFlags { impl GenericUsage for BufferUsageFlags {
@ -37,33 +36,37 @@ impl GenericUsage for TextureUsageFlags {
} }
} }
#[derive(Default)]
pub struct Tracker {
buffers: Mutex<HashMap<Stored<BufferId>, BufferUsageFlags>>,
textures: Mutex<HashMap<Stored<TextureId>, TextureUsageFlags>>,
}
impl Tracker { pub struct Tracker<I, U> {
fn use_impl<I, U>( map: HashMap<Stored<I>, U>,
map: &mut HashMap<I, U>, id: I, usage: U, permit: UsePermit }
) -> Result<UseAction<U>, U> pub type BufferTracker = Tracker<BufferId, BufferUsageFlags>;
where pub type TextureTracker = Tracker<TextureId, TextureUsageFlags>;
impl<
I: Hash + Eq, I: Hash + Eq,
U: Copy + GenericUsage + BitOr<Output = U> + PartialEq, U: Copy + GenericUsage + BitOr<Output = U> + PartialEq,
{ > Tracker<I, U> {
match map.entry(id) { pub fn new() -> Self {
Tracker {
map: HashMap::new(),
}
}
pub fn track(&mut self, id: I, usage: U, permit: TrackPermit) -> Result<Tracktion<U>, U> {
match self.map.entry(Stored(id)) {
Entry::Vacant(e) => { Entry::Vacant(e) => {
e.insert(usage); e.insert(usage);
Ok(UseAction::Init) Ok(Tracktion::Init)
} }
Entry::Occupied(mut e) => { Entry::Occupied(mut e) => {
let old = *e.get(); let old = *e.get();
if usage == old { if usage == old {
Ok(UseAction::Keep) Ok(Tracktion::Keep)
} else if permit.contains(UsePermit::EXTEND) && !(old | usage).is_exclusive() { } else if permit.contains(TrackPermit::EXTEND) && !(old | usage).is_exclusive() {
Ok(UseAction::Extend { old: e.insert(old | usage) }) Ok(Tracktion::Extend { old: e.insert(old | usage) })
} else if permit.contains(UsePermit::REPLACE) { } else if permit.contains(TrackPermit::REPLACE) {
Ok(UseAction::Replace { old: e.insert(usage) }) Ok(Tracktion::Replace { old: e.insert(usage) })
} else { } else {
Err(old) Err(old)
} }
@ -71,15 +74,7 @@ impl Tracker {
} }
} }
pub(crate) fn use_buffer( pub(crate) fn finish(self) -> HashMap<Stored<I>, U> {
&self, id: Stored<BufferId>, usage: BufferUsageFlags, permit: UsePermit, self.map
) -> Result<UseAction<BufferUsageFlags>, BufferUsageFlags> {
Self::use_impl(&mut *self.buffers.lock().unwrap(), id, usage, permit)
}
pub(crate) fn use_texture(
&self, id: Stored<TextureId>, usage: TextureUsageFlags, permit: UsePermit,
) -> Result<UseAction<TextureUsageFlags>, TextureUsageFlags> {
Self::use_impl(&mut *self.textures.lock().unwrap(), id, usage, permit)
} }
} }