wgpu backend: --camera flag + request adapter's max buffer limits

Two pieces that block proper side-by-side parity with the GL minimal:

1. --camera tx,ty,tz,dist,yaw,pitch. Same format string as the GL
   minimal so a pasted camera arg lands the same view on both backends.
   setCamera() also flips initial_view_applied_ = true so the auto-
   viewAll-on-first-load doesn't snap away from the script-set position
   when the model finishes uploading.

2. Real BIM models exceed the conservative WebGPU defaults at device
   create time. A 114k-instance / 19M-index sidecar's vertex storage is
   139 MB, which trips wgpu's default 128 MB max_storage_buffer_binding_
   size and bind-group creation fails. Now wgpuAdapterGetLimits is
   called first and the device is requested at the adapter's full
   ceiling — every desktop driver supports multi-GB.

   Trade-off worth flagging: web parity will fail here because browsers
   cap at the defaults. The eventual fix is to split a model's vertex/
   instance storage into ≤128 MB chunks with a small per-frame routing
   table, which is a real chunk of work. For now this unblocks all the
   native benchmarking the user is actually doing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-05-27 14:58:18 +10:00
parent f9a9273ecc
commit 7893135790
3 changed files with 55 additions and 2 deletions
+26
View File
@@ -631,7 +631,19 @@ bool WgpuViewportWindow::initWgpu() {
struct DeviceReq { WGPUDevice device = nullptr; bool done = false; bool ok = false; };
DeviceReq dreq;
// Query what the adapter can do, and request the same headroom on the
// device so a single large model's vertex/instance storage buffer doesn't
// hit the conservative defaults (128 MB binding, 256 MB buffer). Real
// BIM models routinely cross 100 MB of vertex bytes; without this the
// first applyCachedModel fails with a bind-group validation error.
//
// For eventual web parity this needs revisiting — browsers cap at the
// defaults — but native targets always support the requested ceilings.
WGPULimits adapter_limits = {};
wgpuAdapterGetLimits(adapter_, &adapter_limits);
WGPUDeviceDescriptor dev_desc = {};
dev_desc.requiredLimits = &adapter_limits;
// Surface uncaptured errors (validation failures etc.) into qWarning so
// they're attributable rather than silently swallowed.
dev_desc.uncapturedErrorCallbackInfo.callback = onUncapturedError;
@@ -1543,6 +1555,20 @@ bool WgpuViewportWindow::computeSceneAabb(float mn[3], float mx[3]) const {
return any;
}
void WgpuViewportWindow::setCamera(float tx, float ty, float tz,
float dist, float yaw_deg, float pitch_deg) {
camera_target_[0] = tx;
camera_target_[1] = ty;
camera_target_[2] = tz;
camera_distance_ = std::max(0.01f, dist);
camera_yaw_deg_ = yaw_deg;
camera_pitch_deg_ = std::clamp(pitch_deg, -89.9f, 89.9f);
// Suppress the auto-viewAll on the first model load so the script-set
// camera survives. Manual viewAll() calls after this still work.
initial_view_applied_ = true;
if (isExposed()) requestUpdate();
}
void WgpuViewportWindow::viewAll() {
float mn[3], mx[3];
if (!computeSceneAabb(mn, mx)) return;