graphics: tighten retirement drain budgets and surface frame-maintenance timing

This commit is contained in:
mchughalex 2026-07-21 05:51:30 +01:00
parent 2a234c6b7c
commit a50f2c8a43
2 changed files with 47 additions and 10 deletions

View file

@ -904,13 +904,41 @@ class NrDeviceD3D12 : public nrhi::Device {
uint32_t height, nrhi::Texture** guest_output_out) {
guest_output_state_ = guest_output_internal_state;
cmd_.ResetFrameState();
const auto maint_t0 = std::chrono::steady_clock::now();
const size_t dissolved_count = dissolved_views_.size();
FlushDissolvedViews();
const auto drain_t0 = std::chrono::steady_clock::now();
size_t released = 0;
size_t backlog = 0;
{
std::lock_guard<std::mutex> lock(mutex_);
// Bounded per frame: the eviction sweeps retire thousands of objects
// at once, and releasing them all in one frame is its own hitch (the
// remainder drains over the following frames).
DrainRetired(cp_->GetCompletedSubmission(), 512);
// remainder drains over the following frames). Committed-resource
// releases are kernel-priced, so the budget stays small.
released = DrainRetired(cp_->GetCompletedSubmission(), 256);
backlog = retired_.size();
}
// Frame-maintenance attribution (this work runs outside the app's
// RenderScene timers, so a sustained cost here is otherwise invisible).
// Throttled 8 per 5 s.
const auto maint_end = std::chrono::steady_clock::now();
const int64_t maint_us =
std::chrono::duration_cast<std::chrono::microseconds>(maint_end - maint_t0).count();
if (maint_us >= 2000) {
static std::chrono::steady_clock::time_point s_window_start{};
static uint32_t s_window_count = 0;
if (maint_end - s_window_start > std::chrono::seconds(5)) {
s_window_start = maint_end;
s_window_count = 0;
}
if (++s_window_count <= 8) {
const int64_t drain_us =
std::chrono::duration_cast<std::chrono::microseconds>(maint_end - drain_t0).count();
REXLOG_INFO(
"nrhi-d3d12: SLOW frame maintenance {}us: dissolve={}us/{} drain={}us/{} backlog={}",
maint_us, maint_us - drain_us, dissolved_count, drain_us, released, backlog);
}
}
NrTextureD3D12*& wrapper = guest_outputs_[guest_output_resource];
if (wrapper != nullptr &&
@ -1047,7 +1075,7 @@ class NrDeviceD3D12 : public nrhi::Device {
uint32_t count;
};
void DrainRetired(uint64_t completed, size_t max_objects = SIZE_MAX) {
size_t DrainRetired(uint64_t completed, size_t max_objects = SIZE_MAX) {
size_t released = 0;
std::erase_if(retired_, [&](const RetiredObject& r) {
if (r.submission < completed && released < max_objects) {
@ -1062,6 +1090,7 @@ class NrDeviceD3D12 : public nrhi::Device {
srv_slots_.Drain(completed);
rtv_slots_.Drain(completed);
dsv_slots_.Drain(completed);
return released;
}
void DestroyGuestOutputWrapperLocked(NrTextureD3D12* wrapper) {

View file

@ -1262,8 +1262,9 @@ class NrDeviceVulkan : public nrhi::Device {
std::lock_guard<std::mutex> lock(mutex_);
// Bounded per frame: the eviction sweeps retire thousands of objects
// at once, and destroying them all in one frame is its own hitch (the
// remainder drains over the following frames).
DrainRetired(cp_->GetCompletedSubmission(), 512);
// remainder drains over the following frames). 256 objects measured
// ~5 ms worst case through the allocator.
DrainRetired(cp_->GetCompletedSubmission(), 256);
}
++frame_index_;
if ((frame_index_ % 600) == 0) {
@ -1282,11 +1283,18 @@ class NrDeviceVulkan : public nrhi::Device {
(unsigned long long)(budgets[i].usage >> 20),
(unsigned long long)(budgets[i].budget >> 20));
}
REXLOG_INFO("nrhi-vulkan mem: {} | bufs upload dl={}MB host={}MB, default dl={}MB host={}MB",
line, g_buf_bytes_upload_dl.load(std::memory_order_relaxed) >> 20,
g_buf_bytes_upload_host.load(std::memory_order_relaxed) >> 20,
g_buf_bytes_default_dl.load(std::memory_order_relaxed) >> 20,
g_buf_bytes_default_host.load(std::memory_order_relaxed) >> 20);
size_t retired_backlog = 0;
{
std::lock_guard<std::mutex> lock(mutex_);
retired_backlog = retired_.size();
}
REXLOG_INFO(
"nrhi-vulkan mem: {} | bufs upload dl={}MB host={}MB, default dl={}MB host={}MB | "
"retired={}",
line, g_buf_bytes_upload_dl.load(std::memory_order_relaxed) >> 20,
g_buf_bytes_upload_host.load(std::memory_order_relaxed) >> 20,
g_buf_bytes_default_dl.load(std::memory_order_relaxed) >> 20,
g_buf_bytes_default_host.load(std::memory_order_relaxed) >> 20, retired_backlog);
}
ring_region_base_ = uint32_t(frame_index_ % kRingRegions) * kRingRegionSize;
ring_region_offset_ = 0;