mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-07 12:56:26 +00:00
ifcviewer: detect web pool-grow OOM via provisional sub-buffers
On web we skip the desktop error-scope spin-wait (it blocks the JS event
loop and hangs the page). The old web addSubBuffer then judged success by
`buf != nullptr` — but Dawn-web returns a NON-NULL error buffer on OOM,
so the pool committed an invalid sub-buffer, alloc handed out slices in
it, and every chunk_bind_group built against it failed ("BindGroup is
invalid" spam + a wgpuQueueSubmit panic). Loading a model larger than the
browser's WebGPU budget triggered exactly this.
Add the grown sub-buffer as *provisional* (alloc and the capacity/free
tallies skip it) and validate it through a non-blocking AllowSpontaneous
PopErrorScope. resolveProvisionalGrowth() clears the flag when it's good,
or drops the sub-buffer and latches growth_disabled_ on a real OOM — at
which point the streaming evictor bounds the working set to what fits
instead of cascading. Only one provisional grow is in flight at a time
(growth_pending_). Desktop keeps its synchronous halve-retry path
unchanged. All 100 unit tests still pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -132,6 +132,11 @@ private:
|
||||
uint64_t capacity = 0;
|
||||
uint64_t used = 0;
|
||||
std::vector<FreeRange> free_ranges;
|
||||
// Web-only: true between addSubBuffer creating the buffer and the
|
||||
// async error scope confirming it didn't OOM. alloc() and the
|
||||
// capacity/free tallies skip provisional sub-pools so an
|
||||
// unvalidated (possibly invalid) buffer is never handed out.
|
||||
bool provisional = false;
|
||||
};
|
||||
|
||||
// Append a new sub-buffer to the pool. Starts at last_growth_size_
|
||||
@@ -148,6 +153,15 @@ private:
|
||||
// refused, at which point growth_disabled_ latches.
|
||||
bool addSubBuffer();
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
// Web-only async-growth resolver. Called from the AllowSpontaneous
|
||||
// PopErrorScope callback addSubBuffer arms: `failed` true means the
|
||||
// provisional sub-buffer OOM'd → drop it and latch growth_disabled_;
|
||||
// false means it's good → clear its provisional flag so alloc can use
|
||||
// it. Clears growth_pending_ either way.
|
||||
void resolveProvisionalGrowth(bool failed);
|
||||
#endif
|
||||
|
||||
std::vector<SubPool> sub_pools_;
|
||||
|
||||
WGPUInstance instance_ = nullptr;
|
||||
@@ -162,6 +176,10 @@ private:
|
||||
// subsequent grow is wasted work.
|
||||
uint64_t last_growth_size_ = 0;
|
||||
bool growth_disabled_ = false;
|
||||
// Web-only: a provisional sub-buffer is awaiting async OOM validation.
|
||||
// Blocks a second concurrent grow so a stalled validation can't spawn
|
||||
// a pile of sub-buffers.
|
||||
bool growth_pending_ = false;
|
||||
std::string label_prefix_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user