Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ jobs:
key: ${{ runner.os }}-shared-${{ hashFiles('native/shared/Cargo.lock') }}
restore-keys: ${{ runner.os }}-shared-

- name: Select hosted Windows shader compiler
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
# WARP's DXIL optimizer can crash during concurrent traversal shader
# compilation. Keep this software-renderer lane on explicit FXC;
# physical DX12/DXC qualification remains a separate requirement.
"WGPU_BACKEND=dx12" >> $env:GITHUB_ENV
"WGPU_DX12_COMPILER=fxc" >> $env:GITHUB_ENV

- name: quick / shared-tests
# Retain adapter identities and capability skips even when Rust reports
# an early-returning GPU test as "ok".
Expand Down
10 changes: 7 additions & 3 deletions docs/evidence/windows-camera-history-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,15 @@ ignored goldens, and two ignored documentation examples retain their status.
Formatting, strict Clippy policy, and repository contracts also pass. The DX12
run uses a process-local Vulkan loader override for older helper functions;
some of those helpers explicitly use software adapters. The golden captures
require a physical GPU and identify the Radeon/backend. Hosted validation is
pending. The Windows hosted library access violation is separate and
remains unresolved. This advances #135/#149/#140 without closing the wider
require a physical GPU and identify the Radeon/backend. Hosted #163 passes the
macOS shared suite, including all 93 goldens and the expanded camera-cut test,
plus canonical Metal captures. Windows native builds and all 20 example links
pass; its shared library stage still crashes before goldens. That access
violation is separate and remains unresolved. This advances #135/#149/#140 without closing the wider
performance, platform, representative-corpus, or hardware requirements.

Source patches, commands, exact RGBA/PNG captures, changed-pixel coordinates,
and results are retained under
`tools/quality/out/windows-engine-plan/camera-cut-dx12/`.
The [published archive](https://github.com/Bloom-Engine/engine/releases/tag/quality-evidence-camera-history-20260911)
includes exact source-match receipts and the failed Windows hosted log.
44 changes: 44 additions & 0 deletions docs/evidence/windows-warp-compiler-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Hosted Windows software-renderer compiler

The actual Windows shared job crashes with `0xc0000005` on #162 and #163.
The native engine build and all 20 example links pass. The Windows crash occurs
in the library stage, before golden tests execute; successful build jobs do not
qualify those render tests.

## Local diagnosis

At unchanged #163 source `c643b85`, four-thread library execution also crashes
when the virtual-geometry helpers select the Microsoft Basic Render Driver.
An eight-thread run passes, so a passing rerun does not close the defect.
Windows Event 1000 identifies `d3d10warp.dll` version `10.0.26100.9278`.

The installed Windows debugger captures a second-chance access violation in
`d3d10warp!JITBaseVariable::OptimizeCopy`, through the WARP DXIL shader-JIT
destructor and compute-pipeline compilation, during a traversal queue submission.
The affected Rust test refines atomic groups that straddle frustum planes.
This identifies the failing driver/compiler path; it does not establish the
underlying driver's root cause or prove that every hosted crash has this stack.

That existing test passes twice alone with DXC and twice with FXC. The complete
ten-test hierarchy group passes serially with DXC, crashes in both four-thread
DXC controls, and passes with FXC and four threads. Complete library controls with four and eight threads also
pass with FXC selected for environment-aware helpers (489 passed, one ignored).
Older helpers ignored compiler/backend environment options during those controls;
some explicitly select software adapters and others select the physical Radeon.

## Compatibility change

The hosted Windows shared lane explicitly selects DX12 and FXC. The remaining
ordinary GPU test helpers now honor backend and compiler environment options,
matching the visibility, virtual-geometry, and golden helpers. Adapter selection,
capability requirements, ignored tests, assertions and thresholds are unchanged.
The ray-query golden helper retains its deliberate DXC requirement.

This is a software-renderer CI workaround. The WARP/DXIL access violation remains
open, and physical DX12/DXC qualification remains required. The ordinary Windows
engine compiler policy is unchanged. The candidate's library suite passes with
four threads and explicit FXC (489 passed, one ignored). Complete local shared
components and hosted validation are still running.

Diagnostic commands, logs, debugger stacks, executable hashes and results are
retained in `tools/quality/out/windows-engine-plan/windows-shared-crash/`.
7 changes: 6 additions & 1 deletion docs/windows-engine-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ audit are saved in `tools/quality/out/windows-engine-plan/plan-requirements.json
The expanded local DX12 goldens expose a [camera-history reset defect](evidence/windows-camera-history-v1.md);
its read guard passes exact fresh/reset comparisons after eight and 40
history frames on Vulkan and DX12. Both complete local shared components
now pass, including all 93 goldens; hosted validation remains required.
now pass, including all 93 goldens. Hosted #163 also passes all 93 macOS
goldens and the expanded cut check; its [evidence is published](https://github.com/Bloom-Engine/engine/releases/tag/quality-evidence-camera-history-20260911).
The Windows library crash reproduces locally inside WARP's DXIL shader
optimizer during concurrent traversal tests. An [explicit FXC hosted lane](evidence/windows-warp-compiler-v1.md)
and consistent test compiler selection are being validated. The underlying
WARP/DXIL defect and physical DX12/DXC acceptance remain separate.
2. Finish all-example native linking, real starter/example startup, and clean
Windows installation. The [native example gate](evidence/windows-example-gate-v1.md)
passes all 20 links locally using Perry 0.5.1220 and one matching source-built
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/cooked_texture_store_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ fn temporary_store(label: &str) -> PathBuf {

fn try_device(require_bc: bool) -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter =
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/renderer/gpu_driven.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1816,7 +1816,8 @@ mod tests {
use wgpu::util::DeviceExt as _;

let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let Ok(adapter) =
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/renderer/impulse_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@ mod tests {
/// without storage textures" doc-comment contract).
fn try_create_device() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
Expand Down
6 changes: 5 additions & 1 deletion native/shared/src/renderer/material_indirection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,11 @@ mod tests {

#[cfg(not(target_arch = "wasm32"))]
fn try_tier_a_device() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
force_fallback_adapter: false,
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/renderer/material_system_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ mod tests {
/// (test skips gracefully) when no GPU is available.
fn try_create_device() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/renderer/occlusion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,8 @@ mod tests {

fn try_device() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter =
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/renderer/planar_reflection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,8 @@ mod tests {
/// is available so the test skips gracefully on bare CI.
fn try_create_device() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/renderer/post_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ mod tests {
/// `transient.rs` so tests run on machines without a real GPU.
fn try_create_device() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/renderer/transient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,8 @@ mod tests {
/// need a device are skipped gracefully.
fn try_create_device() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
Expand Down
3 changes: 2 additions & 1 deletion native/shared/src/virtual_shadow_gpu_receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,8 @@ mod tests {

fn try_device() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter =
Expand Down
3 changes: 2 additions & 1 deletion native/shared/tests/render_targets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use bloom_shared::scene::SceneGraph;

fn try_renderer() -> Option<Renderer> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::all()),
backend_options: wgpu::BackendOptions::from_env_or_default(),
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let adapter =
Expand Down
Loading