WIP: cross-platform
This commit is contained in:
@@ -7,9 +7,11 @@ use serde::de::DeserializeOwned;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::gpu::Wgpu;
|
||||
use crate::graph::{Binding, Execution, Extent, Pass, RenderGraph, RenderPipeline, Texture};
|
||||
use crate::graph::{self, Binding, Execution, Extent, Pass, RenderGraph, RenderPipeline, Texture};
|
||||
use crate::render_data::RenderData;
|
||||
|
||||
pub mod profiler;
|
||||
|
||||
pub struct GpuResources {
|
||||
pub buffers: HashMap<String, GpuBuffer>,
|
||||
pub textures: Vec<GpuTexture>,
|
||||
@@ -18,21 +20,7 @@ pub struct GpuResources {
|
||||
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
||||
pub compute_pipelines: HashMap<String, wgpu::ComputePipeline>,
|
||||
pub passes: Vec<GpuPass>,
|
||||
pub profiler: Option<GpuProfiler>,
|
||||
}
|
||||
|
||||
pub struct GpuProfiler {
|
||||
query_set: wgpu::QuerySet,
|
||||
resolve: wgpu::Buffer,
|
||||
readback: Arc<wgpu::Buffer>,
|
||||
query_count: u32,
|
||||
}
|
||||
|
||||
pub struct ProfileMap {
|
||||
readback: Arc<wgpu::Buffer>,
|
||||
state: Arc<AtomicU8>,
|
||||
labels: Vec<String>,
|
||||
timestamp_period: f32,
|
||||
pub profiler: Option<profiler::Profiler>,
|
||||
}
|
||||
|
||||
pub struct GpuBuffer {
|
||||
@@ -175,30 +163,6 @@ impl GpuResources {
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, _>>()?;
|
||||
|
||||
let profiler = (gpu.timestamp_queries && !graph.executions.is_empty()).then(|| {
|
||||
let query_count = graph.executions.len() as u32 * 2;
|
||||
let bytes = u64::from(query_count) * 8;
|
||||
GpuProfiler {
|
||||
query_set: gpu.device.create_query_set(&wgpu::QuerySetDescriptor {
|
||||
label: Some("frame-profile"),
|
||||
ty: wgpu::QueryType::Timestamp,
|
||||
count: query_count,
|
||||
}),
|
||||
resolve: gpu.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("frame-profile-resolve"),
|
||||
size: bytes,
|
||||
usage: wgpu::BufferUsages::QUERY_RESOLVE | wgpu::BufferUsages::COPY_SRC,
|
||||
mapped_at_creation: false,
|
||||
}),
|
||||
readback: Arc::new(gpu.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("frame-profile-readback"),
|
||||
size: bytes,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
})),
|
||||
query_count,
|
||||
}
|
||||
});
|
||||
let mut resources = Self {
|
||||
buffers,
|
||||
textures,
|
||||
@@ -207,7 +171,7 @@ impl GpuResources {
|
||||
render_pipelines,
|
||||
compute_pipelines,
|
||||
passes: Vec::new(),
|
||||
profiler,
|
||||
profiler: None,
|
||||
};
|
||||
for execution in &graph.executions {
|
||||
let compiled = match execution {
|
||||
@@ -256,6 +220,17 @@ impl GpuResources {
|
||||
};
|
||||
resources.passes.push(compiled);
|
||||
}
|
||||
|
||||
let pass_labels = resources
|
||||
.passes
|
||||
.iter()
|
||||
.map(|pass| pass.label().to_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
resources.profiler = (gpu.timestamp_queries && !graph.executions.is_empty()).then(|| {
|
||||
profiler::Profiler::new(&gpu.device, graph.executions.len() as u32, pass_labels)
|
||||
});
|
||||
|
||||
Ok(resources)
|
||||
}
|
||||
|
||||
@@ -308,45 +283,6 @@ impl GpuResources {
|
||||
.is_some_and(|texture| !texture.uploaded_mips.contains(&mip_level))
|
||||
}
|
||||
|
||||
pub fn render_timestamps(&self, pass: usize) -> Option<wgpu::RenderPassTimestampWrites<'_>> {
|
||||
self.profiler
|
||||
.as_ref()
|
||||
.map(|profiler| wgpu::RenderPassTimestampWrites {
|
||||
query_set: &profiler.query_set,
|
||||
beginning_of_pass_write_index: Some(pass as u32 * 2),
|
||||
end_of_pass_write_index: Some(pass as u32 * 2 + 1),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_timestamps(&self, pass: usize) -> Option<wgpu::ComputePassTimestampWrites<'_>> {
|
||||
self.profiler
|
||||
.as_ref()
|
||||
.map(|profiler| wgpu::ComputePassTimestampWrites {
|
||||
query_set: &profiler.query_set,
|
||||
beginning_of_pass_write_index: Some(pass as u32 * 2),
|
||||
end_of_pass_write_index: Some(pass as u32 * 2 + 1),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn resolve_profile(&self, encoder: &mut wgpu::CommandEncoder) {
|
||||
let Some(profiler) = &self.profiler else {
|
||||
return;
|
||||
};
|
||||
encoder.resolve_query_set(
|
||||
&profiler.query_set,
|
||||
0..profiler.query_count,
|
||||
&profiler.resolve,
|
||||
0,
|
||||
);
|
||||
encoder.copy_buffer_to_buffer(
|
||||
&profiler.resolve,
|
||||
0,
|
||||
&profiler.readback,
|
||||
0,
|
||||
u64::from(profiler.query_count) * 8,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn map_profile(&self, timestamp_period: f32) -> Option<ProfileMap> {
|
||||
let profiler = self.profiler.as_ref()?;
|
||||
let state = Arc::new(AtomicU8::new(0));
|
||||
@@ -448,11 +384,13 @@ impl GpuResources {
|
||||
.render_pipelines
|
||||
.get(&pass.pipeline)
|
||||
.ok_or("GRAPH_PIPELINE")?;
|
||||
|
||||
let pipeline_changed = previous_pipeline != Some(pass.pipeline.as_str());
|
||||
if pipeline_changed {
|
||||
encoder.set_pipeline(pipeline);
|
||||
previous_pipeline = Some(pass.pipeline.as_str());
|
||||
}
|
||||
|
||||
if pipeline_changed || previous_bindings != Some(pass.bindings.as_slice()) {
|
||||
for (group, bind_group) in
|
||||
self.bind_groups(pass, |group| pipeline.get_bind_group_layout(group), gpu)?
|
||||
|
||||
Reference in New Issue
Block a user