feat: new draw command with arguments and resource tracking
This commit is contained in:
parent
d896a207de
commit
d901fe250b
|
|
@ -3,7 +3,9 @@ use ash::vk;
|
||||||
use crate::{
|
use crate::{
|
||||||
recorder::{CommandIndex, CommandRecorder, RecordError, RecordedCommand, SideEffectMap},
|
recorder::{CommandIndex, CommandRecorder, RecordError, RecordedCommand, SideEffectMap},
|
||||||
resources::{
|
resources::{
|
||||||
Buffer, BufferRange, ResourceId, SubresourceScope, SubresourceScopeInner, Texture,
|
Buffer, BufferRange, DescriptorResourceAccess, GraphDescriptorSet, IndexBinding,
|
||||||
|
IndexFormat, IndirectBinding, PushConstantData, ResourceId, SubresourceScope,
|
||||||
|
SubresourceScopeInner, Texture, VertexBinding,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -120,27 +122,205 @@ impl RecordedCommand for ClearTexture {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum DrawArgs {
|
||||||
|
Direct {
|
||||||
|
vertex_count: u32,
|
||||||
|
instance_count: u32,
|
||||||
|
first_vertex: u32,
|
||||||
|
first_instance: u32,
|
||||||
|
},
|
||||||
|
Indexed {
|
||||||
|
index_count: u32,
|
||||||
|
instance_count: u32,
|
||||||
|
first_index: u32,
|
||||||
|
vertex_offset: i32,
|
||||||
|
first_instance: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A self-contained graphics draw packet. Every graph resource consumed by
|
||||||
|
/// vertex/index/indirect input or descriptor sets is declared by this packet.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Draw {
|
pub struct Draw {
|
||||||
pub vertex_count: u32,
|
pub args: DrawArgs,
|
||||||
pub instance_count: u32,
|
/// Layout compatible with the bound pipeline, descriptor sets, and push constants.
|
||||||
pub first_vertex: u32,
|
pub pipeline_layout: vk::PipelineLayout,
|
||||||
pub first_instance: u32,
|
pub vertices: Vec<VertexBinding>,
|
||||||
|
pub index: Option<IndexBinding>,
|
||||||
|
pub indirect: Option<IndirectBinding>,
|
||||||
|
pub descriptor_sets: Vec<GraphDescriptorSet>,
|
||||||
|
pub push_constants: Vec<PushConstantData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command for Draw {
|
impl Command for Draw {
|
||||||
fn side_effects(&self, _command_index: CommandIndex, _map: &mut SideEffectMap) {}
|
fn side_effects(&self, command_index: CommandIndex, map: &mut SideEffectMap) {
|
||||||
|
for vertex in &self.vertices {
|
||||||
|
map.insert(
|
||||||
|
command_index,
|
||||||
|
vertex.slice.buffer.id(),
|
||||||
|
access(
|
||||||
|
vk::PipelineStageFlags2::VERTEX_INPUT,
|
||||||
|
vk::AccessFlags2::VERTEX_ATTRIBUTE_READ,
|
||||||
|
SubresourceScopeInner::Buffer(vertex.slice.range),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some(index) = self.index {
|
||||||
|
map.insert(
|
||||||
|
command_index,
|
||||||
|
index.slice.buffer.id(),
|
||||||
|
access(
|
||||||
|
vk::PipelineStageFlags2::INDEX_INPUT,
|
||||||
|
vk::AccessFlags2::INDEX_READ,
|
||||||
|
SubresourceScopeInner::Buffer(index.slice.range),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some(indirect) = self.indirect {
|
||||||
|
map.insert(
|
||||||
|
command_index,
|
||||||
|
indirect.slice.buffer.id(),
|
||||||
|
access(
|
||||||
|
vk::PipelineStageFlags2::DRAW_INDIRECT,
|
||||||
|
vk::AccessFlags2::INDIRECT_COMMAND_READ,
|
||||||
|
SubresourceScopeInner::Buffer(indirect.slice.range),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for set in &self.descriptor_sets {
|
||||||
|
for declared in &set.accesses {
|
||||||
|
let scope = match *declared {
|
||||||
|
DescriptorResourceAccess::Buffer {
|
||||||
|
range,
|
||||||
|
stage,
|
||||||
|
access: mask,
|
||||||
|
..
|
||||||
|
} => access(stage, mask, SubresourceScopeInner::Buffer(range)),
|
||||||
|
DescriptorResourceAccess::Texture {
|
||||||
|
range,
|
||||||
|
layout,
|
||||||
|
stage,
|
||||||
|
access: mask,
|
||||||
|
..
|
||||||
|
} => access(
|
||||||
|
stage,
|
||||||
|
mask,
|
||||||
|
SubresourceScopeInner::Texture { range, layout },
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let resource = match *declared {
|
||||||
|
DescriptorResourceAccess::Buffer { buffer, .. } => buffer.id(),
|
||||||
|
DescriptorResourceAccess::Texture { texture, .. } => texture.id(),
|
||||||
|
};
|
||||||
|
map.insert(command_index, resource, scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecordedCommand for Draw {
|
impl RecordedCommand for Draw {
|
||||||
fn apply(&mut self, recorder: &mut CommandRecorder<'_>) -> Result<(), RecordError> {
|
fn apply(&mut self, recorder: &mut CommandRecorder<'_>) -> Result<(), RecordError> {
|
||||||
|
for vertex in &self.vertices {
|
||||||
|
let buffers = [recorder.buffer(vertex.slice.buffer.id())?];
|
||||||
|
let offsets = [vertex.slice.range.offset];
|
||||||
|
unsafe {
|
||||||
|
recorder.device.cmd_bind_vertex_buffers(
|
||||||
|
recorder.command_buffer,
|
||||||
|
vertex.binding,
|
||||||
|
&buffers,
|
||||||
|
&offsets,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(index) = self.index {
|
||||||
|
let index_type = match index.format {
|
||||||
|
IndexFormat::Uint8 => vk::IndexType::UINT8_KHR,
|
||||||
|
IndexFormat::Uint16 => vk::IndexType::UINT16,
|
||||||
|
IndexFormat::Uint32 => vk::IndexType::UINT32,
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
recorder.device.cmd_bind_index_buffer(
|
||||||
|
recorder.command_buffer,
|
||||||
|
recorder.buffer(index.slice.buffer.id())?,
|
||||||
|
index.slice.range.offset,
|
||||||
|
index_type,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for constants in &self.push_constants {
|
||||||
|
unsafe {
|
||||||
|
recorder.device.cmd_push_constants(
|
||||||
|
recorder.command_buffer,
|
||||||
|
self.pipeline_layout,
|
||||||
|
constants.stage_flags,
|
||||||
|
constants.offset,
|
||||||
|
&constants.data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let descriptor_sets: Vec<_> = self.descriptor_sets.iter().map(|set| set.raw).collect();
|
||||||
|
if !descriptor_sets.is_empty() {
|
||||||
|
unsafe {
|
||||||
|
recorder.device.cmd_bind_descriptor_sets(
|
||||||
|
recorder.command_buffer,
|
||||||
|
vk::PipelineBindPoint::GRAPHICS,
|
||||||
|
self.pipeline_layout,
|
||||||
|
0,
|
||||||
|
&descriptor_sets,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
recorder.device.cmd_draw(
|
if let Some(indirect) = self.indirect {
|
||||||
recorder.command_buffer,
|
let buffer = recorder.buffer(indirect.slice.buffer.id())?;
|
||||||
self.vertex_count,
|
if matches!(self.args, DrawArgs::Indexed { .. }) {
|
||||||
self.instance_count,
|
recorder.device.cmd_draw_indexed_indirect(
|
||||||
self.first_vertex,
|
recorder.command_buffer,
|
||||||
self.first_instance,
|
buffer,
|
||||||
);
|
indirect.slice.range.offset,
|
||||||
|
indirect.draw_count,
|
||||||
|
indirect.stride,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
recorder.device.cmd_draw_indirect(
|
||||||
|
recorder.command_buffer,
|
||||||
|
buffer,
|
||||||
|
indirect.slice.range.offset,
|
||||||
|
indirect.draw_count,
|
||||||
|
indirect.stride,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match self.args {
|
||||||
|
DrawArgs::Direct {
|
||||||
|
vertex_count,
|
||||||
|
instance_count,
|
||||||
|
first_vertex,
|
||||||
|
first_instance,
|
||||||
|
} => recorder.device.cmd_draw(
|
||||||
|
recorder.command_buffer,
|
||||||
|
vertex_count,
|
||||||
|
instance_count,
|
||||||
|
first_vertex,
|
||||||
|
first_instance,
|
||||||
|
),
|
||||||
|
DrawArgs::Indexed {
|
||||||
|
index_count,
|
||||||
|
instance_count,
|
||||||
|
first_index,
|
||||||
|
vertex_offset,
|
||||||
|
first_instance,
|
||||||
|
} => recorder.device.cmd_draw_indexed(
|
||||||
|
recorder.command_buffer,
|
||||||
|
index_count,
|
||||||
|
instance_count,
|
||||||
|
first_index,
|
||||||
|
vertex_offset,
|
||||||
|
first_instance,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ use renderer_device::QueueFamilyIndex;
|
||||||
use crate::{
|
use crate::{
|
||||||
recorder::{CommandIndex, CommandList, CommandRecorder, RecordError, scope_range},
|
recorder::{CommandIndex, CommandList, CommandRecorder, RecordError, scope_range},
|
||||||
resources::{
|
resources::{
|
||||||
Buffer, GraphBufferDesc, GraphTextureDesc, ResourceDesc, ResourceId, Subresource,
|
Buffer, DescriptorResourceAccess, GraphBufferDesc, GraphDescriptorSet, GraphTextureDesc,
|
||||||
SubresourceScope, SubresourceScopeInner, Texture, access_flag_is_write,
|
ResourceDesc, ResourceId, Subresource, SubresourceScope, SubresourceScopeInner, Texture,
|
||||||
|
access_flag_is_write,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -244,6 +245,19 @@ impl RenderGraph {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Associate graph-visible resource accesses with a raw Vulkan descriptor set.
|
||||||
|
///
|
||||||
|
/// The caller is responsible for declaring every resource referenced by the
|
||||||
|
/// set accurately; compilation validates that each declared resource belongs
|
||||||
|
/// to this graph, but cannot inspect the raw descriptor contents.
|
||||||
|
pub fn track_descriptor_set(
|
||||||
|
&self,
|
||||||
|
raw: vk::DescriptorSet,
|
||||||
|
accesses: Vec<DescriptorResourceAccess>,
|
||||||
|
) -> GraphDescriptorSet {
|
||||||
|
GraphDescriptorSet { raw, accesses }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push<C: crate::commands::Command + 'static>(&mut self, command: C) -> CommandIndex {
|
pub fn push<C: crate::commands::Command + 'static>(&mut self, command: C) -> CommandIndex {
|
||||||
self.commands.push(command)
|
self.commands.push(command)
|
||||||
}
|
}
|
||||||
|
|
@ -923,8 +937,11 @@ fn texture_size_estimate(desc: &GraphTextureDesc) -> u64 {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{ClearTexture, CopyBuffer},
|
commands::{ClearTexture, CopyBuffer, Draw, DrawArgs},
|
||||||
resources::{BufferRange, GraphBufferDesc, GraphTextureDesc, ResourceDesc},
|
resources::{
|
||||||
|
BufferRange, BufferSlice, GraphBufferDesc, GraphTextureDesc, IndexBinding, IndexFormat,
|
||||||
|
IndirectBinding, ResourceDesc, VertexBinding,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -1079,6 +1096,237 @@ mod tests {
|
||||||
assert!(compiled.interference().interferes(src.id(), dst.id()));
|
assert!(compiled.interference().interferes(src.id(), dst.id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn draw_vertex_index_and_indirect_reads_follow_copies_and_derive_usage() {
|
||||||
|
let mut graph = RenderGraph::new();
|
||||||
|
let source = graph.create_buffer(GraphBufferDesc {
|
||||||
|
size: 64,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let vertex = graph.create_buffer(GraphBufferDesc {
|
||||||
|
size: 64,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let index = graph.create_buffer(GraphBufferDesc {
|
||||||
|
size: 64,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let indirect = graph.create_buffer(GraphBufferDesc {
|
||||||
|
size: 64,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let range = BufferRange {
|
||||||
|
offset: 0,
|
||||||
|
size: 64,
|
||||||
|
};
|
||||||
|
for dst in [vertex, index, indirect] {
|
||||||
|
graph.push(CopyBuffer {
|
||||||
|
src: source,
|
||||||
|
src_range: range,
|
||||||
|
dst,
|
||||||
|
dst_range: range,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
graph.push(Draw {
|
||||||
|
args: DrawArgs::Indexed {
|
||||||
|
index_count: 3,
|
||||||
|
instance_count: 1,
|
||||||
|
first_index: 0,
|
||||||
|
vertex_offset: 0,
|
||||||
|
first_instance: 0,
|
||||||
|
},
|
||||||
|
pipeline_layout: vk::PipelineLayout::null(),
|
||||||
|
vertices: vec![VertexBinding {
|
||||||
|
binding: 0,
|
||||||
|
slice: BufferSlice {
|
||||||
|
buffer: vertex,
|
||||||
|
range,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
index: Some(IndexBinding {
|
||||||
|
slice: BufferSlice {
|
||||||
|
buffer: index,
|
||||||
|
range,
|
||||||
|
},
|
||||||
|
format: IndexFormat::Uint16,
|
||||||
|
}),
|
||||||
|
indirect: Some(IndirectBinding {
|
||||||
|
slice: BufferSlice {
|
||||||
|
buffer: indirect,
|
||||||
|
range,
|
||||||
|
},
|
||||||
|
draw_count: 1,
|
||||||
|
stride: 20,
|
||||||
|
}),
|
||||||
|
descriptor_sets: Vec::new(),
|
||||||
|
push_constants: Vec::new(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let accesses = graph.commands.side_effects.command_accesses();
|
||||||
|
assert_eq!(
|
||||||
|
derive_buffer_usage(
|
||||||
|
&accesses_for_resource(vertex.id(), accesses),
|
||||||
|
vk::BufferUsageFlags::empty()
|
||||||
|
),
|
||||||
|
vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
derive_buffer_usage(
|
||||||
|
&accesses_for_resource(index.id(), accesses),
|
||||||
|
vk::BufferUsageFlags::empty()
|
||||||
|
),
|
||||||
|
vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
derive_buffer_usage(
|
||||||
|
&accesses_for_resource(indirect.id(), accesses),
|
||||||
|
vk::BufferUsageFlags::empty()
|
||||||
|
),
|
||||||
|
vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDIRECT_BUFFER
|
||||||
|
);
|
||||||
|
|
||||||
|
let compiled = graph.compile().expect("graph compiles");
|
||||||
|
assert_eq!(compiled.batches().len(), 2);
|
||||||
|
assert_eq!(
|
||||||
|
compiled.batches()[0],
|
||||||
|
[CommandIndex(0), CommandIndex(1), CommandIndex(2)]
|
||||||
|
);
|
||||||
|
assert_eq!(compiled.batches()[1], [CommandIndex(3)]);
|
||||||
|
let draw_barrier = compiled
|
||||||
|
.barriers()
|
||||||
|
.iter()
|
||||||
|
.find(|barrier| barrier.before_command == CommandIndex(3))
|
||||||
|
.expect("draw input barriers are generated");
|
||||||
|
assert_eq!(draw_barrier.resources.len(), 3);
|
||||||
|
assert!(
|
||||||
|
draw_barrier
|
||||||
|
.resources
|
||||||
|
.iter()
|
||||||
|
.any(|resource| resource.id == vertex.id())
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
draw_barrier
|
||||||
|
.resources
|
||||||
|
.iter()
|
||||||
|
.any(|resource| resource.id == index.id())
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
draw_barrier
|
||||||
|
.resources
|
||||||
|
.iter()
|
||||||
|
.any(|resource| resource.id == indirect.id())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn descriptor_set_declarations_create_buffer_and_texture_accesses() {
|
||||||
|
let mut graph = RenderGraph::new();
|
||||||
|
let source = graph.create_buffer(GraphBufferDesc {
|
||||||
|
size: 32,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let uniform = graph.create_buffer(GraphBufferDesc {
|
||||||
|
size: 32,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let texture = graph.create_texture(GraphTextureDesc {
|
||||||
|
format: vk::Format::R8G8B8A8_UNORM,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let buffer_range = BufferRange {
|
||||||
|
offset: 0,
|
||||||
|
size: 32,
|
||||||
|
};
|
||||||
|
graph.push(CopyBuffer {
|
||||||
|
src: source,
|
||||||
|
src_range: buffer_range,
|
||||||
|
dst: uniform,
|
||||||
|
dst_range: buffer_range,
|
||||||
|
});
|
||||||
|
graph.push(ClearTexture {
|
||||||
|
texture,
|
||||||
|
range: texture_range(vk::ImageAspectFlags::COLOR, 0, 1, 0, 1),
|
||||||
|
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
color: [0.0; 4],
|
||||||
|
});
|
||||||
|
let set = graph.track_descriptor_set(
|
||||||
|
vk::DescriptorSet::null(),
|
||||||
|
vec![
|
||||||
|
DescriptorResourceAccess::Buffer {
|
||||||
|
buffer: uniform,
|
||||||
|
range: buffer_range,
|
||||||
|
stage: vk::PipelineStageFlags2::VERTEX_SHADER,
|
||||||
|
access: vk::AccessFlags2::UNIFORM_READ,
|
||||||
|
},
|
||||||
|
DescriptorResourceAccess::Texture {
|
||||||
|
texture,
|
||||||
|
range: texture_range(vk::ImageAspectFlags::COLOR, 0, 1, 0, 1),
|
||||||
|
layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
stage: vk::PipelineStageFlags2::FRAGMENT_SHADER,
|
||||||
|
access: vk::AccessFlags2::SHADER_SAMPLED_READ,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
graph.push(Draw {
|
||||||
|
args: DrawArgs::Direct {
|
||||||
|
vertex_count: 3,
|
||||||
|
instance_count: 1,
|
||||||
|
first_vertex: 0,
|
||||||
|
first_instance: 0,
|
||||||
|
},
|
||||||
|
pipeline_layout: vk::PipelineLayout::null(),
|
||||||
|
vertices: Vec::new(),
|
||||||
|
index: None,
|
||||||
|
indirect: None,
|
||||||
|
descriptor_sets: vec![set],
|
||||||
|
push_constants: Vec::new(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let accesses = graph.commands.side_effects.command_accesses();
|
||||||
|
assert!(
|
||||||
|
derive_buffer_usage(
|
||||||
|
&accesses_for_resource(uniform.id(), accesses),
|
||||||
|
vk::BufferUsageFlags::empty()
|
||||||
|
)
|
||||||
|
.contains(vk::BufferUsageFlags::UNIFORM_BUFFER)
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
derive_image_usage(
|
||||||
|
&accesses_for_resource(texture.id(), accesses),
|
||||||
|
vk::ImageUsageFlags::empty()
|
||||||
|
)
|
||||||
|
.contains(vk::ImageUsageFlags::SAMPLED)
|
||||||
|
);
|
||||||
|
|
||||||
|
let compiled = graph.compile().expect("graph compiles");
|
||||||
|
let draw_barrier = compiled
|
||||||
|
.barriers()
|
||||||
|
.iter()
|
||||||
|
.find(|barrier| barrier.before_command == CommandIndex(2))
|
||||||
|
.expect("descriptor accesses produce barriers");
|
||||||
|
assert_eq!(draw_barrier.resources.len(), 2);
|
||||||
|
let texture_barrier = draw_barrier
|
||||||
|
.resources
|
||||||
|
.iter()
|
||||||
|
.find(|resource| resource.id == texture.id())
|
||||||
|
.expect("sampled texture barrier is present");
|
||||||
|
assert_eq!(
|
||||||
|
texture_barrier.new_layout,
|
||||||
|
Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
texture_barrier.dst_access,
|
||||||
|
vk::AccessFlags2::SHADER_SAMPLED_READ
|
||||||
|
);
|
||||||
|
assert!(compiled.resource_lifetimes().contains_key(&uniform.id()));
|
||||||
|
assert!(compiled.resource_lifetimes().contains_key(&texture.id()));
|
||||||
|
assert!(
|
||||||
|
compiled
|
||||||
|
.interference()
|
||||||
|
.interferes(uniform.id(), texture.id())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn write_then_read_creates_order_and_barrier() {
|
fn write_then_read_creates_order_and_barrier() {
|
||||||
let mut graph = RenderGraph::new();
|
let mut graph = RenderGraph::new();
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,8 @@ pub mod resources;
|
||||||
|
|
||||||
pub use graph::{CompiledGraph, GraphError, RenderGraph, ResourceInterference};
|
pub use graph::{CompiledGraph, GraphError, RenderGraph, ResourceInterference};
|
||||||
pub use recorder::{CommandIndex, CommandList, CommandRecorder, SideEffectMap};
|
pub use recorder::{CommandIndex, CommandList, CommandRecorder, SideEffectMap};
|
||||||
pub use resources::{Buffer, GraphBufferDesc, GraphTextureDesc, ResourceId, Texture};
|
pub use resources::{
|
||||||
|
Buffer, BufferRange, BufferSlice, DescriptorResourceAccess, GraphBufferDesc,
|
||||||
|
GraphDescriptorSet, GraphTextureDesc, IndexBinding, IndexFormat, IndirectBinding,
|
||||||
|
PushConstantData, ResourceId, Texture, VertexBinding,
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,79 @@ impl BufferRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A graph buffer together with the byte range used by a command.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct BufferSlice {
|
||||||
|
pub buffer: Buffer,
|
||||||
|
pub range: BufferRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A vertex-input binding. `binding` is the Vulkan vertex binding number.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct VertexBinding {
|
||||||
|
pub binding: u32,
|
||||||
|
pub slice: BufferSlice,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum IndexFormat {
|
||||||
|
Uint8,
|
||||||
|
Uint16,
|
||||||
|
Uint32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct IndexBinding {
|
||||||
|
pub slice: BufferSlice,
|
||||||
|
pub format: IndexFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct IndirectBinding {
|
||||||
|
pub slice: BufferSlice,
|
||||||
|
/// Number of draw commands in the indirect buffer.
|
||||||
|
pub draw_count: u32,
|
||||||
|
/// Stride in bytes between draw commands. Must satisfy Vulkan's alignment
|
||||||
|
/// and minimum-size requirements for the corresponding draw command.
|
||||||
|
pub stride: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum DescriptorResourceAccess {
|
||||||
|
Buffer {
|
||||||
|
buffer: Buffer,
|
||||||
|
range: BufferRange,
|
||||||
|
stage: vk::PipelineStageFlags2,
|
||||||
|
access: vk::AccessFlags2,
|
||||||
|
},
|
||||||
|
Texture {
|
||||||
|
texture: Texture,
|
||||||
|
range: vk::ImageSubresourceRange,
|
||||||
|
layout: vk::ImageLayout,
|
||||||
|
stage: vk::PipelineStageFlags2,
|
||||||
|
access: vk::AccessFlags2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Vulkan descriptor set accompanied by graph-visible resource accesses.
|
||||||
|
///
|
||||||
|
/// Callers must list every resource used by the set with its accurate range,
|
||||||
|
/// pipeline stage, access mask, and (for textures) image layout. The graph can
|
||||||
|
/// track these declarations, but cannot inspect or verify raw descriptor-set
|
||||||
|
/// contents.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GraphDescriptorSet {
|
||||||
|
pub raw: vk::DescriptorSet,
|
||||||
|
pub accesses: Vec<DescriptorResourceAccess>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PushConstantData {
|
||||||
|
pub stage_flags: vk::ShaderStageFlags,
|
||||||
|
pub offset: u32,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Subresource {
|
pub enum Subresource {
|
||||||
Buffer(BufferRange),
|
Buffer(BufferRange),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue