core: indirect draw passes, device feature list, drop handles-specific bundle heuristics
Amp-Thread-ID: https://ampcode.com/threads/T-01a0b2dd-db32-712d-99ce-12ce4a86d979 Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
@@ -212,22 +212,14 @@ impl GpuResources {
|
||||
for execution in &graph.executions {
|
||||
let compiled = match execution {
|
||||
Execution::Render(passes) => {
|
||||
let (bundle, draws) = resources.render_bundle(graph, passes, gpu)?;
|
||||
let (bundle, draws) = resources.render_bundle(graph, passes, gpu, data)?;
|
||||
let first = &graph.passes[passes[0]].id;
|
||||
let last = &graph.passes[*passes.last().unwrap()].id;
|
||||
GpuPass::Render {
|
||||
label: if passes.len() == 1 {
|
||||
graph.passes[passes[0]].id.clone()
|
||||
} else if passes
|
||||
.iter()
|
||||
.all(|index| graph.passes[*index].id.starts_with("forward-"))
|
||||
{
|
||||
format!("Forward ({draws} draws)")
|
||||
} else if passes
|
||||
.iter()
|
||||
.all(|index| graph.passes[*index].id.starts_with("depth-"))
|
||||
{
|
||||
format!("Depth ({draws} draws)")
|
||||
format!("{first} ({draws} draws)")
|
||||
} else {
|
||||
format!("Render ({draws} draws)")
|
||||
format!("{first} … {last} ({draws} draws)")
|
||||
},
|
||||
first: passes[0],
|
||||
last: *passes.last().unwrap(),
|
||||
@@ -405,6 +397,7 @@ impl GpuResources {
|
||||
graph: &RenderGraph,
|
||||
passes: &[usize],
|
||||
gpu: &Wgpu,
|
||||
data: &RenderData,
|
||||
) -> Result<(wgpu::RenderBundle, usize), String> {
|
||||
let pass = &graph.passes[passes[0]];
|
||||
let declaration = graph
|
||||
@@ -441,9 +434,8 @@ impl GpuResources {
|
||||
let mut previous_pipeline = None;
|
||||
let mut previous_bindings: Option<&[Binding]> = None;
|
||||
let mut draws = 0;
|
||||
let mut at = 0;
|
||||
while at < passes.len() {
|
||||
let pass = &graph.passes[passes[at]];
|
||||
for &at in passes {
|
||||
let pass = &graph.passes[at];
|
||||
let pipeline = self
|
||||
.render_pipelines
|
||||
.get(&pass.pipeline)
|
||||
@@ -469,7 +461,7 @@ impl GpuResources {
|
||||
.buffer;
|
||||
encoder.set_vertex_buffer(binding.slot, buffer.slice(binding.offset..));
|
||||
}
|
||||
if let Some(binding) = &pass.index_buffer {
|
||||
let indexed = if let Some(binding) = &pass.index_buffer {
|
||||
let buffer = &self
|
||||
.buffers
|
||||
.get(&binding.resource)
|
||||
@@ -479,26 +471,53 @@ impl GpuResources {
|
||||
buffer.slice(binding.offset..),
|
||||
parse(&binding.format, "GRAPH_INDEX_FORMAT")?,
|
||||
);
|
||||
let mut instances = pass.draw.instances;
|
||||
while at + 1 < passes.len()
|
||||
&& can_instance(pass, &graph.passes[passes[at + 1]], instances)
|
||||
{
|
||||
at += 1;
|
||||
instances += graph.passes[passes[at]].draw.instances;
|
||||
}
|
||||
encoder.draw_indexed(
|
||||
pass.draw.first_index..pass.draw.first_index + pass.draw.indices,
|
||||
pass.draw.base_vertex,
|
||||
pass.draw.first_instance..pass.draw.first_instance + instances,
|
||||
);
|
||||
true
|
||||
} else {
|
||||
encoder.draw(
|
||||
pass.draw.first_vertex..pass.draw.first_vertex + pass.draw.vertices,
|
||||
pass.draw.first_instance..pass.draw.first_instance + pass.draw.instances,
|
||||
);
|
||||
false
|
||||
};
|
||||
match (&pass.indirect, indexed) {
|
||||
(Some(indirect), indexed) => {
|
||||
let buffer = self
|
||||
.buffers
|
||||
.get(&indirect.resource)
|
||||
.ok_or("GRAPH_RESOURCE_UNKNOWN")?;
|
||||
let rows = data.rows(&buffer.source).ok_or("GRAPH_ARRAY_UNKNOWN")?;
|
||||
let end = match indirect.count {
|
||||
Some(count) => indirect.first.checked_add(count),
|
||||
None => Some(rows.rows),
|
||||
}
|
||||
.filter(|end| indirect.first <= *end && *end <= rows.rows)
|
||||
.ok_or("GRAPH_INDIRECT")?;
|
||||
if rows.stride < if indexed { 20 } else { 16 } {
|
||||
return Err("GRAPH_INDIRECT".into());
|
||||
}
|
||||
let count = end - indirect.first;
|
||||
for row in indirect.first..end {
|
||||
let offset = u64::from(row) * u64::from(rows.stride);
|
||||
if indexed {
|
||||
encoder.draw_indexed_indirect(&buffer.buffer, offset);
|
||||
} else {
|
||||
encoder.draw_indirect(&buffer.buffer, offset);
|
||||
}
|
||||
}
|
||||
draws += count as usize;
|
||||
}
|
||||
(None, true) => {
|
||||
encoder.draw_indexed(
|
||||
pass.draw.first_index..pass.draw.first_index + pass.draw.indices,
|
||||
pass.draw.base_vertex,
|
||||
pass.draw.first_instance..pass.draw.first_instance + pass.draw.instances,
|
||||
);
|
||||
draws += 1;
|
||||
}
|
||||
(None, false) => {
|
||||
encoder.draw(
|
||||
pass.draw.first_vertex..pass.draw.first_vertex + pass.draw.vertices,
|
||||
pass.draw.first_instance..pass.draw.first_instance + pass.draw.instances,
|
||||
);
|
||||
draws += 1;
|
||||
}
|
||||
}
|
||||
draws += 1;
|
||||
at += 1;
|
||||
}
|
||||
Ok((
|
||||
encoder.finish(&wgpu::RenderBundleDescriptor {
|
||||
@@ -554,18 +573,6 @@ impl GpuResources {
|
||||
}
|
||||
}
|
||||
|
||||
fn can_instance(first: &Pass, next: &Pass, instances: u32) -> bool {
|
||||
first.pipeline == next.pipeline
|
||||
&& first.bindings == next.bindings
|
||||
&& first.vertex_buffers == next.vertex_buffers
|
||||
&& first.index_buffer == next.index_buffer
|
||||
&& first.draw.indices != 0
|
||||
&& first.draw.indices == next.draw.indices
|
||||
&& first.draw.first_index == next.draw.first_index
|
||||
&& first.draw.base_vertex == next.draw.base_vertex
|
||||
&& first.draw.first_instance + instances == next.draw.first_instance
|
||||
}
|
||||
|
||||
impl GpuPass {
|
||||
fn label(&self) -> &str {
|
||||
match self {
|
||||
|
||||
Reference in New Issue
Block a user