Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions goud_engine/src/libs/graphics/backend/wgpu_backend/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ impl FrameOps for WgpuBackend {
crate::libs::profiling::profile_scope!(WGPU_BEGIN_FRAME);

frame_timing::reset_timings();
if let Some(gpu_timestamps) = self.gpu_timestamps.as_mut() {
gpu_timestamps.poll_ready_results(&self.device);
gpu_timestamps.record_latest_timings();
}

let surface = match self.surface.as_ref() {
Some(s) => s,
Expand Down Expand Up @@ -63,6 +67,7 @@ impl FrameOps for WgpuBackend {
crate::libs::profiling::finish_frame!();
return Err(GoudError::InvalidState("No active frame".into()));
};
let timestamp_readback_slot;

let mut encoder = self
.device
Expand Down Expand Up @@ -137,6 +142,9 @@ impl FrameOps for WgpuBackend {

// -- render_pass phase ----------------------------------------------------
let render_pass_start = std::time::Instant::now();
if let Some(gpu_timestamps) = self.gpu_timestamps.as_ref() {
gpu_timestamps.write_render_begin(&mut encoder);
}
{
crate::libs::profiling::profile_scope!(WGPU_RENDER_PASS);

Expand All @@ -159,7 +167,10 @@ impl FrameOps for WgpuBackend {
}),
stencil_ops: None,
}),
timestamp_writes: None,
timestamp_writes: self
.gpu_timestamps
.as_ref()
.and_then(|gpu_timestamps| gpu_timestamps.render_pass_writes()),
occlusion_query_set: None,
multiview_mask: None,
});
Expand Down Expand Up @@ -241,6 +252,9 @@ impl FrameOps for WgpuBackend {
}
}
}
if let Some(gpu_timestamps) = self.gpu_timestamps.as_ref() {
gpu_timestamps.write_render_end(&mut encoder);
}
let render_pass_us = render_pass_start.elapsed().as_micros() as u64;
frame_timing::record_phase("render_pass", render_pass_us);

Expand Down Expand Up @@ -275,10 +289,16 @@ impl FrameOps for WgpuBackend {
{
crate::libs::profiling::profile_scope!(WGPU_GPU_SUBMIT);

timestamp_readback_slot = self
.gpu_timestamps
.as_mut()
.and_then(|gpu_timestamps| gpu_timestamps.resolve_into_readback(&mut encoder));
self.queue.submit(std::iter::once(encoder.finish()));
}
let submit_us = submit_start.elapsed().as_micros() as u64;
frame_timing::record_phase("gpu_submit", submit_us);
if self.gpu_timestamps.is_none() {
frame_timing::record_phase("gpu_submit", submit_us);
}

// -- readback_stall phase ---------------------------------------------
let readback_start = std::time::Instant::now();
Expand All @@ -295,10 +315,16 @@ impl FrameOps for WgpuBackend {
{
crate::libs::profiling::profile_scope!(WGPU_GPU_SUBMIT);

timestamp_readback_slot = self
.gpu_timestamps
.as_mut()
.and_then(|gpu_timestamps| gpu_timestamps.resolve_into_readback(&mut encoder));
self.queue.submit(std::iter::once(encoder.finish()));
}
let submit_us = submit_start.elapsed().as_micros() as u64;
frame_timing::record_phase("gpu_submit", submit_us);
if self.gpu_timestamps.is_none() {
frame_timing::record_phase("gpu_submit", submit_us);
}

self.last_frame_readback = None;
}
Expand All @@ -308,6 +334,11 @@ impl FrameOps for WgpuBackend {
frame.surface_texture.present();
let present_us = present_start.elapsed().as_micros() as u64;
frame_timing::record_phase("surface_present", present_us);
if let (Some(gpu_timestamps), Some(slot)) =
(self.gpu_timestamps.as_mut(), timestamp_readback_slot)
{
gpu_timestamps.begin_readback(slot);
}

crate::libs::profiling::finish_frame!();

Expand Down
10 changes: 7 additions & 3 deletions goud_engine/src/libs/graphics/backend/wgpu_backend/init.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! wgpu backend initialization: device/surface setup and public accessors.

use super::{
BackendCapabilities, BackendInfo, BlendFactor, CullFace, DepthFunc, FrontFace, HashMap,
PrimitiveTopology, ShaderLanguage, TextureOps, WgpuBackend,
timestamps::GpuTimestampQueries, BackendCapabilities, BackendInfo, BlendFactor, CullFace,
DepthFunc, FrontFace, HashMap, PrimitiveTopology, ShaderLanguage, TextureOps, WgpuBackend,
};
use crate::core::{
error::{GoudError, GoudResult},
Expand Down Expand Up @@ -40,10 +40,11 @@ impl WgpuBackend {
.await
.map_err(|e| GoudError::BackendNotSupported(format!("No suitable GPU adapter: {e}")))?;

let timestamp_features = GpuTimestampQueries::requested_features(adapter.features());
let (device, queue): (wgpu::Device, wgpu::Queue) = adapter
.request_device(&wgpu::DeviceDescriptor {
label: Some("GoudEngine"),
required_features: wgpu::Features::empty(),
required_features: timestamp_features,
required_limits: wgpu::Limits::default(),
..Default::default()
})
Expand Down Expand Up @@ -241,6 +242,8 @@ impl WgpuBackend {
})
};

let gpu_timestamps = GpuTimestampQueries::new(&device, &queue, device.features());

Ok(Self {
info,
device,
Expand Down Expand Up @@ -307,6 +310,7 @@ impl WgpuBackend {
scratch_shadow_pipeline_keys: Vec::new(),
scratch_shadow_offsets: Vec::new(),
scratch_shadow_grown_shaders: rustc_hash::FxHashSet::default(),
gpu_timestamps,
})
}

Expand Down
4 changes: 4 additions & 0 deletions goud_engine/src/libs/graphics/backend/wgpu_backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ mod switch_init;
#[cfg(feature = "switch-vulkan")]
pub(crate) mod switch_surface;
mod texture;
mod timestamp_probe;
mod timestamps;
mod uniforms;
#[cfg(feature = "xbox-gdk")]
mod xbox_init;
Expand All @@ -57,6 +59,7 @@ use resources::{
};

pub use init::{MAX_TEXTURE_UNITS, UNIFORM_BUFFER_SIZE};
pub use timestamp_probe::{probe_gpu_timestamp_queries, GpuTimestampProbeReport};

/// Whether to request the wgpu software fallback adapter.
///
Expand Down Expand Up @@ -197,6 +200,7 @@ pub struct WgpuBackend {
/// Scratch set reused each frame to dedupe shadow uniform-buffer growth
/// per shader, avoiding a per-frame FxHashSet allocation.
scratch_shadow_grown_shaders: rustc_hash::FxHashSet<ShaderHandle>,
gpu_timestamps: Option<timestamps::GpuTimestampQueries>,
}

// SAFETY: wgpu Device and Queue are Send+Sync. Surface is Send.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ impl WgpuBackend {
scratch_shadow_pipeline_keys: Vec::new(),
scratch_shadow_offsets: Vec::new(),
scratch_shadow_grown_shaders: rustc_hash::FxHashSet::default(),
gpu_timestamps: None,
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ impl WgpuBackend {
/// `shadow_draw_commands` after execution.
pub(super) fn execute_shadow_pass(&mut self, encoder: &mut wgpu::CommandEncoder) {
if self.shadow_draw_commands.is_empty() || self.shadow_depth_view.is_none() {
if let Some(gpu_timestamps) = self.gpu_timestamps.as_ref() {
gpu_timestamps.write_empty_shadow_phase(encoder);
}
return;
}

Expand Down Expand Up @@ -374,6 +377,9 @@ impl WgpuBackend {
// SAFETY: shadow_depth_view is confirmed Some above.
let shadow_view = self.shadow_depth_view.as_ref().unwrap();

if let Some(gpu_timestamps) = self.gpu_timestamps.as_ref() {
gpu_timestamps.write_shadow_begin(encoder);
}
{
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("shadow-pass"),
Expand All @@ -386,7 +392,10 @@ impl WgpuBackend {
}),
stencil_ops: None,
}),
timestamp_writes: None,
timestamp_writes: self
.gpu_timestamps
.as_ref()
.and_then(|gpu_timestamps| gpu_timestamps.shadow_pass_writes()),
occlusion_query_set: None,
multiview_mask: None,
});
Expand Down Expand Up @@ -439,6 +448,9 @@ impl WgpuBackend {
}
}
}
if let Some(gpu_timestamps) = self.gpu_timestamps.as_ref() {
gpu_timestamps.write_shadow_end(encoder);
}
self.shadow_draw_commands.clear();
// Return scratch buffers so they are reused next frame.
self.scratch_shadow_pipeline_keys = shadow_keys;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ impl WgpuBackend {
scratch_shadow_pipeline_keys: Vec::new(),
scratch_shadow_offsets: Vec::new(),
scratch_shadow_grown_shaders: rustc_hash::FxHashSet::default(),
gpu_timestamps: None,
})
}
}
Loading
Loading