graphics: attribute native-pass GPU time to per-stage profile buckets
This commit is contained in:
parent
95d2792585
commit
17caf72bdd
4 changed files with 151 additions and 0 deletions
|
|
@ -398,6 +398,26 @@ struct Rect {
|
||||||
int32_t bottom = 0;
|
int32_t bottom = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// GPU-time attribution stages for ProfileRegion: the renderer marks the start
|
||||||
|
// of each of its passes and the command processor's timestamp-bucket profiler
|
||||||
|
// (d3d12_gpu_timestamp_buckets / vulkan_gpu_timestamp_buckets) reports the
|
||||||
|
// per-stage GPU spans. kTail marks the end of the last stage; on Vulkan the
|
||||||
|
// span from kTail to frame end is reported as its own bucket, on D3D12 it
|
||||||
|
// stays in the profiler's untimed remainder.
|
||||||
|
enum class ProfileStage : uint8_t {
|
||||||
|
kCommit, // content-store commits, decode uploads, eviction
|
||||||
|
kShadow, // dynamic caster shadow atlas + blur
|
||||||
|
kStaticSun, // static sun-shadow cascade renders
|
||||||
|
kMain, // main scene pass (opaque + transparent)
|
||||||
|
kResolve, // MSAA resolve + outline composite
|
||||||
|
kAmbientOcclusion,
|
||||||
|
kSsr,
|
||||||
|
kVolumetrics,
|
||||||
|
kBloom, // bloom pyramid + tonemap
|
||||||
|
k2d, // photo grab, blur chains, 2D overlay replay
|
||||||
|
kTail, // after the last stage: backend/present tail
|
||||||
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Command recording. Wraps the command processor's deferred command list for
|
// Command recording. Wraps the command processor's deferred command list for
|
||||||
// the current frame; valid only inside the render callback, render thread
|
// the current frame; valid only inside the render callback, render thread
|
||||||
|
|
@ -469,6 +489,11 @@ class Cmd {
|
||||||
ResourceState after) = 0;
|
ResourceState after) = 0;
|
||||||
virtual void FlushBarriers() = 0;
|
virtual void FlushBarriers() = 0;
|
||||||
|
|
||||||
|
// Marks the start of a renderer pass for GPU-time attribution (closing the
|
||||||
|
// previously marked stage). No-op while the backend's timestamp-bucket
|
||||||
|
// profiler is disabled; see ProfileStage for the reporting semantics.
|
||||||
|
virtual void ProfileRegion(ProfileStage stage) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~Cmd() = default;
|
virtual ~Cmd() = default;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,20 @@ enum class DrawBucket : uint8_t {
|
||||||
// The native guest-output renderer's whole GPU pass (scene + 2D replay +
|
// The native guest-output renderer's whole GPU pass (scene + 2D replay +
|
||||||
// resolve), recorded inside IssueSwap. Runs until frame end.
|
// resolve), recorded inside IssueSwap. Runs until frame end.
|
||||||
kNativeScene,
|
kNativeScene,
|
||||||
|
// Native-pass stages (nrhi::Cmd::ProfileRegion): successive marks partition
|
||||||
|
// the native pass into its renderer-defined stages; when the renderer marks
|
||||||
|
// them, they replace kNativeScene in the frame's attribution.
|
||||||
|
kNativeCommit, // content-store commits, decode uploads, eviction
|
||||||
|
kNativeShadow, // dynamic caster shadow atlas + blur
|
||||||
|
kNativeSun, // static sun-shadow cascade renders
|
||||||
|
kNativeMain, // main scene pass (opaque + transparent + SSR G-buffer)
|
||||||
|
kNativeResolve, // MSAA resolve + outline composite
|
||||||
|
kNativeAo, // screen-space ambient occlusion
|
||||||
|
kNativeSsr, // screen-space reflection march + composite
|
||||||
|
kNativeVol, // volumetric sun shafts + haze
|
||||||
|
kNativeBloom, // bloom pyramid + tonemap
|
||||||
|
kNative2d, // photo grab, blur chains, 2D overlay replay
|
||||||
|
kNativeTail, // after the last stage: backend/present tail
|
||||||
kCount,
|
kCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -103,6 +117,28 @@ inline const char* DrawBucketName(DrawBucket bucket) {
|
||||||
return "TexUpCopy";
|
return "TexUpCopy";
|
||||||
case DrawBucket::kNativeScene:
|
case DrawBucket::kNativeScene:
|
||||||
return "Native";
|
return "Native";
|
||||||
|
case DrawBucket::kNativeCommit:
|
||||||
|
return "NatCommit";
|
||||||
|
case DrawBucket::kNativeShadow:
|
||||||
|
return "NatShadow";
|
||||||
|
case DrawBucket::kNativeSun:
|
||||||
|
return "NatSun";
|
||||||
|
case DrawBucket::kNativeMain:
|
||||||
|
return "NatMain";
|
||||||
|
case DrawBucket::kNativeResolve:
|
||||||
|
return "NatResolve";
|
||||||
|
case DrawBucket::kNativeAo:
|
||||||
|
return "NatAO";
|
||||||
|
case DrawBucket::kNativeSsr:
|
||||||
|
return "NatSSR";
|
||||||
|
case DrawBucket::kNativeVol:
|
||||||
|
return "NatVol";
|
||||||
|
case DrawBucket::kNativeBloom:
|
||||||
|
return "NatBloom";
|
||||||
|
case DrawBucket::kNative2d:
|
||||||
|
return "Nat2D";
|
||||||
|
case DrawBucket::kNativeTail:
|
||||||
|
return "NatTail";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -398,6 +398,7 @@ class NrCmdD3D12 : public nrhi::Cmd {
|
||||||
void Barrier(nrhi::Texture* texture, ResourceState before,
|
void Barrier(nrhi::Texture* texture, ResourceState before,
|
||||||
ResourceState after) override;
|
ResourceState after) override;
|
||||||
void FlushBarriers() override;
|
void FlushBarriers() override;
|
||||||
|
void ProfileRegion(nrhi::ProfileStage stage) override;
|
||||||
|
|
||||||
// Called at frame begin and on root-signature changes: the fresh deferred
|
// Called at frame begin and on root-signature changes: the fresh deferred
|
||||||
// command list / new root signature carries no bindings, so the latched
|
// command list / new root signature carries no bindings, so the latched
|
||||||
|
|
@ -407,9 +408,20 @@ class NrCmdD3D12 : public nrhi::Cmd {
|
||||||
std::memset(last_table_counts_, 0, sizeof(last_table_counts_));
|
std::memset(last_table_counts_, 0, sizeof(last_table_counts_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frame begin only (never on root-signature changes): each frame gets a
|
||||||
|
// fresh timestamp-query range, so an open profile region must not carry an
|
||||||
|
// end query across frames.
|
||||||
|
void ResetProfileRegion() { profile_region_query_ = UINT32_MAX; }
|
||||||
|
|
||||||
NrDeviceD3D12* device = nullptr;
|
NrDeviceD3D12* device = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Start query of the open ProfileRegion span, UINT32_MAX when none. Unlike
|
||||||
|
// Vulkan's auto-closing regions, D3D12 buckets are explicit begin/end query
|
||||||
|
// pairs; an unended pair would read stale readback memory, so every opened
|
||||||
|
// region is closed by the next mark (kTail closes without opening).
|
||||||
|
uint32_t profile_region_query_ = UINT32_MAX;
|
||||||
|
|
||||||
void BindTextureTable(uint32_t param, NrTextureViewD3D12* const* views, uint32_t count);
|
void BindTextureTable(uint32_t param, NrTextureViewD3D12* const* views, uint32_t count);
|
||||||
|
|
||||||
// Last tuple bound per root param: consecutive draws mostly rebind the
|
// Last tuple bound per root param: consecutive draws mostly rebind the
|
||||||
|
|
@ -936,6 +948,7 @@ class NrDeviceD3D12 : public nrhi::Device {
|
||||||
uint32_t height, nrhi::Texture** guest_output_out) {
|
uint32_t height, nrhi::Texture** guest_output_out) {
|
||||||
guest_output_state_ = guest_output_internal_state;
|
guest_output_state_ = guest_output_internal_state;
|
||||||
cmd_.ResetFrameState();
|
cmd_.ResetFrameState();
|
||||||
|
cmd_.ResetProfileRegion();
|
||||||
const auto maint_t0 = std::chrono::steady_clock::now();
|
const auto maint_t0 = std::chrono::steady_clock::now();
|
||||||
const size_t dissolved_count = dissolved_views_.size();
|
const size_t dissolved_count = dissolved_views_.size();
|
||||||
FlushDissolvedViews();
|
FlushDissolvedViews();
|
||||||
|
|
@ -1417,6 +1430,47 @@ void NrCmdD3D12::Barrier(nrhi::Texture* texture, ResourceState before, ResourceS
|
||||||
|
|
||||||
void NrCmdD3D12::FlushBarriers() { device->cp()->SubmitBarriers(); }
|
void NrCmdD3D12::FlushBarriers() { device->cp()->SubmitBarriers(); }
|
||||||
|
|
||||||
|
rex::perf::DrawBucket ProfileStageBucket(nrhi::ProfileStage stage) {
|
||||||
|
switch (stage) {
|
||||||
|
case nrhi::ProfileStage::kCommit:
|
||||||
|
return rex::perf::DrawBucket::kNativeCommit;
|
||||||
|
case nrhi::ProfileStage::kShadow:
|
||||||
|
return rex::perf::DrawBucket::kNativeShadow;
|
||||||
|
case nrhi::ProfileStage::kStaticSun:
|
||||||
|
return rex::perf::DrawBucket::kNativeSun;
|
||||||
|
case nrhi::ProfileStage::kMain:
|
||||||
|
return rex::perf::DrawBucket::kNativeMain;
|
||||||
|
case nrhi::ProfileStage::kResolve:
|
||||||
|
return rex::perf::DrawBucket::kNativeResolve;
|
||||||
|
case nrhi::ProfileStage::kAmbientOcclusion:
|
||||||
|
return rex::perf::DrawBucket::kNativeAo;
|
||||||
|
case nrhi::ProfileStage::kSsr:
|
||||||
|
return rex::perf::DrawBucket::kNativeSsr;
|
||||||
|
case nrhi::ProfileStage::kVolumetrics:
|
||||||
|
return rex::perf::DrawBucket::kNativeVol;
|
||||||
|
case nrhi::ProfileStage::kBloom:
|
||||||
|
return rex::perf::DrawBucket::kNativeBloom;
|
||||||
|
case nrhi::ProfileStage::k2d:
|
||||||
|
return rex::perf::DrawBucket::kNative2d;
|
||||||
|
case nrhi::ProfileStage::kTail:
|
||||||
|
return rex::perf::DrawBucket::kNativeTail;
|
||||||
|
}
|
||||||
|
return rex::perf::DrawBucket::kNativeScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NrCmdD3D12::ProfileRegion(nrhi::ProfileStage stage) {
|
||||||
|
if (profile_region_query_ != UINT32_MAX) {
|
||||||
|
device->cp()->EndGpuTimestampedDraw(profile_region_query_);
|
||||||
|
profile_region_query_ = UINT32_MAX;
|
||||||
|
}
|
||||||
|
if (stage == nrhi::ProfileStage::kTail) {
|
||||||
|
// No frame-end query to pair with on D3D12; the tail lands in the
|
||||||
|
// profiler's untimed remainder.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
profile_region_query_ = device->cp()->BeginGpuTimestampedDraw(ProfileStageBucket(stage));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
nrhi::Device* CreateNativeRhiDevice(D3D12CommandProcessor* command_processor) {
|
nrhi::Device* CreateNativeRhiDevice(D3D12CommandProcessor* command_processor) {
|
||||||
|
|
|
||||||
|
|
@ -440,6 +440,7 @@ class NrCmdVulkan : public nrhi::Cmd {
|
||||||
uint32_t height) override;
|
uint32_t height) override;
|
||||||
void Barrier(nrhi::Texture* texture, ResourceState before, ResourceState after) override;
|
void Barrier(nrhi::Texture* texture, ResourceState before, ResourceState after) override;
|
||||||
void FlushBarriers() override;
|
void FlushBarriers() override;
|
||||||
|
void ProfileRegion(nrhi::ProfileStage stage) override;
|
||||||
|
|
||||||
// --- frame handling (driven by the device) ---
|
// --- frame handling (driven by the device) ---
|
||||||
void ResetFrameState();
|
void ResetFrameState();
|
||||||
|
|
@ -2693,6 +2694,41 @@ void NrCmdVulkan::FlushBarriers() {
|
||||||
device->cp()->SubmitBarriers(true);
|
device->cp()->SubmitBarriers(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rex::perf::DrawBucket ProfileStageBucket(nrhi::ProfileStage stage) {
|
||||||
|
switch (stage) {
|
||||||
|
case nrhi::ProfileStage::kCommit:
|
||||||
|
return rex::perf::DrawBucket::kNativeCommit;
|
||||||
|
case nrhi::ProfileStage::kShadow:
|
||||||
|
return rex::perf::DrawBucket::kNativeShadow;
|
||||||
|
case nrhi::ProfileStage::kStaticSun:
|
||||||
|
return rex::perf::DrawBucket::kNativeSun;
|
||||||
|
case nrhi::ProfileStage::kMain:
|
||||||
|
return rex::perf::DrawBucket::kNativeMain;
|
||||||
|
case nrhi::ProfileStage::kResolve:
|
||||||
|
return rex::perf::DrawBucket::kNativeResolve;
|
||||||
|
case nrhi::ProfileStage::kAmbientOcclusion:
|
||||||
|
return rex::perf::DrawBucket::kNativeAo;
|
||||||
|
case nrhi::ProfileStage::kSsr:
|
||||||
|
return rex::perf::DrawBucket::kNativeSsr;
|
||||||
|
case nrhi::ProfileStage::kVolumetrics:
|
||||||
|
return rex::perf::DrawBucket::kNativeVol;
|
||||||
|
case nrhi::ProfileStage::kBloom:
|
||||||
|
return rex::perf::DrawBucket::kNativeBloom;
|
||||||
|
case nrhi::ProfileStage::k2d:
|
||||||
|
return rex::perf::DrawBucket::kNative2d;
|
||||||
|
case nrhi::ProfileStage::kTail:
|
||||||
|
return rex::perf::DrawBucket::kNativeTail;
|
||||||
|
}
|
||||||
|
return rex::perf::DrawBucket::kNativeScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NrCmdVulkan::ProfileRegion(nrhi::ProfileStage stage) {
|
||||||
|
// Region semantics: beginning a bucket closes the active one, and the CP
|
||||||
|
// closes the last bucket at frame end - so the kTail mark records the
|
||||||
|
// present/submission tail as its own span.
|
||||||
|
device->cp()->BeginGpuTimestampedRegion(ProfileStageBucket(stage));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue