diff --git a/src/ifcviewer/BufferPool.h b/src/ifcviewer/BufferPool.h index 9f38308e72..5e9811f7a9 100644 --- a/src/ifcviewer/BufferPool.h +++ b/src/ifcviewer/BufferPool.h @@ -123,6 +123,13 @@ public: <= max_total_capacity_bytes_); } + // True once the driver (not the budget) has refused growth even at the + // floor size. On platforms with no memory query this is the only device + // report there is: the owner treats the first refusal as a pressure + // event and carves the required-tier margin out of the cache before a + // required allocation has to fail for it (see ViewportCore::render). + bool growth_was_refused() const { return growth_disabled_; } + // Whether a growth is in flight. On web that window is real time — a // provisional sub-buffer validates asynchronously a frame or two later — so // the streaming driver has to know that free space is still on its way and diff --git a/src/ifcviewer/ViewportCore.cpp b/src/ifcviewer/ViewportCore.cpp index 2acc65d501..f953f566db 100644 --- a/src/ifcviewer/ViewportCore.cpp +++ b/src/ifcviewer/ViewportCore.cpp @@ -7732,6 +7732,24 @@ void ViewportCore::render() { Stopwatch frame_timer; frame_timer.start(); + // The driver refusing pool growth is the query-less platform's device + // report (web has no memory query; the pool just grew until the GPU + // process said no). Answer it once, immediately: lower the budget so + // the required-tier margin comes back out of the cache NOW, instead of + // the next attachment resize having to fail — and paint broken frames — + // before pressure feedback carves the same room. + if (pool_.growth_was_refused() && !pool_growth_refusal_handled_) { + pool_growth_refusal_handled_ = true; + const double mb = 1.0 / (1024.0 * 1024.0); + Log::info() << "[wgpu] driver refused geometry-cache growth at " + << double(pool_.total_capacity_bytes()) * mb + << " MB -- reserving the required-tier margin out of the cache"; + if (budget_.onPressure(pool_.total_capacity_bytes(), + GpuBudget::kFixedMarginBytes, 0)) { + applyBudgetToPool(); + } + } + // Drain any HiZ async readbacks completed since last frame. if (hiz_enabled_) drainHizReadbacks(); diff --git a/src/ifcviewer/ViewportCore.h b/src/ifcviewer/ViewportCore.h index 3890cce69c..3f1365f8e8 100644 --- a/src/ifcviewer/ViewportCore.h +++ b/src/ifcviewer/ViewportCore.h @@ -1155,6 +1155,9 @@ private: void releaseRenderAttachments(); GpuBudget budget_; + // Latch: the pool's first driver-refused growth has been answered by + // carving the margin out of the cache (see render()). + bool pool_growth_refusal_handled_ = false; // Adapter ids, read once at init, for matching the driver's memory // report to the card wgpu is actually using. std::uint32_t adapter_vendor_id_ = 0;