mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
wgpu: query surface capabilities before configuring present mode
Default WGPUPresentMode was a static Mailbox. That works on DX12 and
on Vulkan with most drivers, but the Metal backend in wgpu-native v29
only exposes [Fifo, Immediate], and asking for Mailbox makes
wgpuSurfaceConfigure panic from Rust:
thread '<unnamed>' panicked at src/lib.rs:605:5:
Error in wgpuSurfaceConfigure: Validation Error
Caused by:
Requested present mode Mailbox is not in the list of supported
present modes: [Fifo, Immediate]
fatal runtime error: failed to initiate panic, error 5, aborting
# Fix
Query wgpuSurfaceGetCapabilities and walk a preference list
(Mailbox → FifoRelaxed → Immediate → Fifo), picking the first mode
the surface actually lists. Fifo is the only spec-required mode and
will always be present, so the loop always finds something.
The env override (WGPU_PRESENT_MODE=...) still wins when set, but
also drops back to Fifo if the requested mode isn't supported on the
current backend — no panic.
# Outcomes per backend
DX12 / Vulkan: picks Mailbox (low input lag, our previous default).
Metal (macOS): picks Immediate (Mailbox unavailable). On Metal the
CAMetalLayer presents through CoreAnimation, so the
compositor still vsync-aligns; Immediate is effectively
low-latency-with-no-tearing on macOS.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1947,23 +1947,60 @@ void WgpuViewportWindow::configureSurface(int width_px, int height_px) {
|
|||||||
// immediate — no vsync at all. Frames presented as soon as
|
// immediate — no vsync at all. Frames presented as soon as
|
||||||
// ready, may tear on motion. Useful for raw
|
// ready, may tear on motion. Useful for raw
|
||||||
// throughput benchmarking.
|
// throughput benchmarking.
|
||||||
WGPUPresentMode pm = WGPUPresentMode_Mailbox;
|
// Preference order. Override with WGPU_PRESENT_MODE=...; otherwise we
|
||||||
|
// try Mailbox → FifoRelaxed → Immediate → Fifo and pick the first
|
||||||
|
// mode actually advertised by the surface. Asking for a mode that
|
||||||
|
// the backend doesn't list aborts the process (wgpu-native panics
|
||||||
|
// from Rust at wgpuSurfaceConfigure). On Metal in particular only
|
||||||
|
// Fifo + Immediate are exposed today, so a static Mailbox default
|
||||||
|
// crashes there.
|
||||||
|
WGPUPresentMode preferred[4] = {
|
||||||
|
WGPUPresentMode_Mailbox,
|
||||||
|
WGPUPresentMode_FifoRelaxed,
|
||||||
|
WGPUPresentMode_Immediate,
|
||||||
|
WGPUPresentMode_Fifo,
|
||||||
|
};
|
||||||
const char* pm_name = "mailbox";
|
const char* pm_name = "mailbox";
|
||||||
if (const char* s = std::getenv("WGPU_PRESENT_MODE")) {
|
if (const char* s = std::getenv("WGPU_PRESENT_MODE")) {
|
||||||
if (std::strcmp(s, "fifo") == 0) {
|
WGPUPresentMode override_pm = WGPUPresentMode_Fifo;
|
||||||
pm = WGPUPresentMode_Fifo; pm_name = "fifo";
|
bool known = true;
|
||||||
} else if (std::strcmp(s, "fifo_relaxed") == 0) {
|
if (std::strcmp(s, "fifo") == 0) { override_pm = WGPUPresentMode_Fifo; pm_name = "fifo"; }
|
||||||
pm = WGPUPresentMode_FifoRelaxed; pm_name = "fifo_relaxed";
|
else if (std::strcmp(s, "fifo_relaxed") == 0) { override_pm = WGPUPresentMode_FifoRelaxed; pm_name = "fifo_relaxed"; }
|
||||||
} else if (std::strcmp(s, "mailbox") == 0) {
|
else if (std::strcmp(s, "mailbox") == 0) { override_pm = WGPUPresentMode_Mailbox; pm_name = "mailbox"; }
|
||||||
pm = WGPUPresentMode_Mailbox; pm_name = "mailbox";
|
else if (std::strcmp(s, "immediate") == 0) { override_pm = WGPUPresentMode_Immediate; pm_name = "immediate"; }
|
||||||
} else if (std::strcmp(s, "immediate") == 0) {
|
else {
|
||||||
pm = WGPUPresentMode_Immediate; pm_name = "immediate";
|
known = false;
|
||||||
} else {
|
|
||||||
qWarning().noquote().nospace()
|
qWarning().noquote().nospace()
|
||||||
<< "[wgpu] unknown WGPU_PRESENT_MODE=" << s
|
<< "[wgpu] unknown WGPU_PRESENT_MODE=" << s
|
||||||
<< " (expected fifo|fifo_relaxed|mailbox|immediate); using mailbox";
|
<< " (expected fifo|fifo_relaxed|mailbox|immediate); falling back to preference order";
|
||||||
|
}
|
||||||
|
if (known) {
|
||||||
|
preferred[0] = override_pm;
|
||||||
|
preferred[1] = WGPUPresentMode_Fifo; // Fifo is the only guaranteed-supported mode
|
||||||
|
preferred[2] = preferred[3] = WGPUPresentMode_Fifo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WGPUSurfaceCapabilities caps = {};
|
||||||
|
wgpuSurfaceGetCapabilities(surface_, adapter_, &caps);
|
||||||
|
auto supports = [&](WGPUPresentMode mode) {
|
||||||
|
for (size_t i = 0; i < caps.presentModeCount; ++i) {
|
||||||
|
if (caps.presentModes[i] == mode) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
WGPUPresentMode pm = WGPUPresentMode_Fifo; // spec-guaranteed fallback
|
||||||
|
for (WGPUPresentMode candidate : preferred) {
|
||||||
|
if (supports(candidate)) { pm = candidate; break; }
|
||||||
|
}
|
||||||
|
switch (pm) {
|
||||||
|
case WGPUPresentMode_Mailbox: pm_name = "mailbox"; break;
|
||||||
|
case WGPUPresentMode_FifoRelaxed: pm_name = "fifo_relaxed"; break;
|
||||||
|
case WGPUPresentMode_Immediate: pm_name = "immediate"; break;
|
||||||
|
case WGPUPresentMode_Fifo: pm_name = "fifo"; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
wgpuSurfaceCapabilitiesFreeMembers(caps);
|
||||||
cfg.presentMode = pm;
|
cfg.presentMode = pm;
|
||||||
if (!surface_configured_) {
|
if (!surface_configured_) {
|
||||||
const char* note = "";
|
const char* note = "";
|
||||||
|
|||||||
Reference in New Issue
Block a user