diff --git a/.deny.toml b/.deny.toml index 8448c81e85..718836d0e7 100644 --- a/.deny.toml +++ b/.deny.toml @@ -4,10 +4,10 @@ skip-tree = [ # We never enable loom in any of our dependencies but it causes dupes { name = "loom", version = "0.7.2" }, { name = "windows-sys", version = "0.45" }, - { name = "winit", version = "0.27" }, { name = "winit", version = "0.29" }, { name = "rustc_version", version = "0.2.3" }, { name = "sourcemap", version = "7.1.1" }, + { name = "miniz_oxide", version = "0.7.4" }, ] skip = [ { name = "hlsl-snapshots", version = "0.1.0" }, diff --git a/.github/dependabot.yml b/.github/dependabot.yml index edfc210ef8..dceafcc145 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,7 +16,7 @@ updates: groups: patch-updates: patterns: - - "*" + - "*" update-types: - "minor" - "patch" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cb6a28a19..802c8bd756 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,12 +33,6 @@ env: # # In order to prevent CI regressions, we pin the nightly version. NIGHTLY_VERSION: "nightly-2023-12-17" - # Version of rust used to build the docs with. - # - # This needs to be newer to work around https://github.com/gfx-rs/wgpu/issues/4905. - # - # Once this fix hits stable Rust, we can use that instead of nightly. - DOCS_RUST_VERSION: "nightly-2023-12-17" # This is the MSRV used by `wgpu` itself and all surrounding infrastructure. REPO_MSRV: "1.76" # This is the MSRV used by the `wgpu-core`, `wgpu-hal`, and `wgpu-types` crates, @@ -150,12 +144,6 @@ jobs: rustup override set ${{ env.REPO_MSRV }} cargo -V - # Use special toolchain for rustdoc, see https://github.com/gfx-rs/wgpu/issues/4905 - - name: Install Rustdoc Toolchain - run: | - rustup toolchain install ${{ env.DOCS_RUST_VERSION }} --no-self-update --profile=minimal --component rust-docs --target ${{ matrix.target }} - cargo +${{ env.DOCS_RUST_VERSION }} -V - - name: disable debug shell: bash run: | @@ -196,11 +184,11 @@ jobs: # build for WebGPU cargo clippy --target ${{ matrix.target }} --tests --features glsl,spirv,fragile-send-sync-non-atomic-wasm cargo clippy --target ${{ matrix.target }} --tests --features glsl,spirv - cargo +${{ env.DOCS_RUST_VERSION }} doc --target ${{ matrix.target }} --no-deps --features glsl,spirv + cargo doc --target ${{ matrix.target }} --no-deps --features glsl,spirv # all features cargo clippy --target ${{ matrix.target }} --tests --all-features - cargo +${{ env.DOCS_RUST_VERSION }} doc --target ${{ matrix.target }} --no-deps --all-features + cargo doc --target ${{ matrix.target }} --no-deps --all-features - name: check em if: matrix.kind == 'em' @@ -230,21 +218,20 @@ jobs: cargo clippy --target ${{ matrix.target }} --tests --benches --all-features # build docs - cargo +${{ env.DOCS_RUST_VERSION }} doc --target ${{ matrix.target }} --all-features --no-deps - # wgpu-core docs are not feasible due to - # - # - name: check private item docs - # if: matrix.kind == 'native' - # shell: bash - # run: | - # set -e - # - # # wgpu_core package - # cargo +${{ env.DOCS_RUST_VERSION }} doc --target ${{ matrix.target }} \ - # --package wgpu-core \ - # --package wgpu-hal \ - # --package naga \ - # --all-features --no-deps --document-private-items + cargo doc --target ${{ matrix.target }} --all-features --no-deps + + - name: check private item docs + if: matrix.kind == 'native' + shell: bash + run: | + set -e + + # wgpu_core package + cargo doc --target ${{ matrix.target }} \ + --package wgpu-core \ + --package wgpu-hal \ + --package naga \ + --all-features --no-deps --document-private-items # We run minimal checks on the MSRV of the core crates, ensuring that # its dependency tree does not cause issues for firefox. @@ -632,7 +619,7 @@ jobs: cargo fmt --manifest-path xtask/Cargo.toml -- --check - name: Check for typos - uses: crate-ci/typos@v1.23.6 + uses: crate-ci/typos@v1.24.5 check-cts-runner: # runtime is normally 2 minutes diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index b1c83e53b6..9e5dc27165 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -41,7 +41,7 @@ jobs: if: ${{ failure() }} - name: Deploy the docs - uses: JamesIves/github-pages-deploy-action@v4.6.3 + uses: JamesIves/github-pages-deploy-action@v4.6.4 if: github.ref == 'refs/heads/trunk' with: token: ${{ secrets.WEB_DEPLOY }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e8a6300240..266d4e7f51 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,7 +41,7 @@ jobs: run: cargo xtask run-wasm --no-serve - name: Deploy WebGPU examples - uses: JamesIves/github-pages-deploy-action@v4.6.3 + uses: JamesIves/github-pages-deploy-action@v4.6.4 if: github.ref == 'refs/heads/trunk' with: token: ${{ secrets.WEB_DEPLOY }} diff --git a/CHANGELOG.md b/CHANGELOG.md index fb1bc4a0ca..aafc73b312 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,14 +55,47 @@ which we're hoping to build performance improvements upon in the future. By @wumpf in [#6069](https://github.com/gfx-rs/wgpu/pull/6069), [#6099](https://github.com/gfx-rs/wgpu/pull/6099), [#6100](https://github.com/gfx-rs/wgpu/pull/6100). +#### `wgpu`'s resources no longer have `.global_id()` getters + +`wgpu-core`'s internals no longer use nor need IDs and we are moving towards removing IDs +completely. This is a step in that direction. + +Current users of `.global_id()` are encouraged to make use of the `PartialEq`, `Eq`, `Hash`, `PartialOrd` and `Ord` +traits that have now been implemented for `wgpu` resources. + +By @teoxoy [#6134](https://github.com/gfx-rs/wgpu/pull/6134). + +#### `set_bind_group` now takes an `Option` for the bind group argument. + +https://gpuweb.github.io/gpuweb/#programmable-passes-bind-groups specifies that bindGroup +is nullable. This change is the start of implementing this part of the spec. Callers that +specify a `Some()` value should have unchanged behavior. Handling of `None` values still +needs to be implemented by backends. + +By @bradwerth [#6216](https://github.com/gfx-rs/wgpu/pull/6216). + ### New Features #### Naga -* Support constant evaluation for `firstLeadingBit` and `firstTrailingBit` numeric built-ins in WGSL. Front-ends that translate to these built-ins also benefit from constant evaluation. By @ErichDonGubler in [#5101](https://github.com/gfx-rs/wgpu/pull/5101). +- Support constant evaluation for `firstLeadingBit` and `firstTrailingBit` numeric built-ins in WGSL. Front-ends that translate to these built-ins also benefit from constant evaluation. By @ErichDonGubler in [#5101](https://github.com/gfx-rs/wgpu/pull/5101). +- Add `first` and `either` sampling types for `@interpolate(flat, …)` in WGSL. By @ErichDonGubler in [#6181](https://github.com/gfx-rs/wgpu/pull/6181). +- Support for more atomic ops in the SPIR-V frontend. By @schell in [#5824](https://github.com/gfx-rs/wgpu/pull/5824). + +#### Vulkan + +- Allow using [VK_GOOGLE_display_timing](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_display_timing.html) unsafely with the `VULKAN_GOOGLE_DISPLAY_TIMING` feature. By @DJMcNab in [#6149](https://github.com/gfx-rs/wgpu/pull/6149) ### Bug Fixes +- Fix incorrect hlsl image output type conversion. By @atlv24 in [#6123](https://github.com/gfx-rs/wgpu/pull/6123) +- Fix JS `TypeError` exception in `Instance::request_adapter` when browser doesn't support WebGPU but `wgpu` not compiled with `webgl` support. By @bgr360 in [#6197](https://github.com/gfx-rs/wgpu/pull/6197). + +#### Naga + +- Accept only `vec3` (not `vecN`) for the `cross` built-in. By @ErichDonGubler in [#6171](https://github.com/gfx-rs/wgpu/pull/6171). +- Configure `SourceLanguage` when enabling debug info in SPV-out. By @kvark in [#6256](https://github.com/gfx-rs/wgpu/pull/6256) + #### General - If GL context creation fails retry with GLES. By @Rapdorian in [#5996](https://github.com/gfx-rs/wgpu/pull/5996) @@ -74,17 +107,47 @@ By @wumpf in [#6069](https://github.com/gfx-rs/wgpu/pull/6069), [#6099](https:// - Deduplicate bind group layouts that are created from pipelines with "auto" layouts. By @teoxoy [#6049](https://github.com/gfx-rs/wgpu/pull/6049) - Fix crash when dropping the surface after the device. By @wumpf in [#6052](https://github.com/gfx-rs/wgpu/pull/6052) - Fix error message that is thrown in create_render_pass to no longer say `compute_pass`. By @matthew-wong1 [#6041](https://github.com/gfx-rs/wgpu/pull/6041) +- Add `VideoFrame` to `ExternalImageSource` enum. By @jprochazk in [#6170](https://github.com/gfx-rs/wgpu/pull/6170) +- Document `wgpu_hal` bounds-checking promises, and adapt `wgpu_core`'s lazy initialization logic to the slightly weaker-than-expected guarantees. By @jimblandy in [#6201](https://github.com/gfx-rs/wgpu/pull/6201) + +#### GLES / OpenGL + +- Fix GL debug message callbacks not being properly cleaned up (causing UB). By @Imberflur in [#6114](https://github.com/gfx-rs/wgpu/pull/6114) + +#### Vulkan + +- Vulkan debug labels assumed no interior nul byte. By @DJMcNab in [#6257](https://github.com/gfx-rs/wgpu/pull/6257) +- Add `.index_type(vk::IndexType::NONE_KHR)` when creating `AccelerationStructureGeometryTrianglesDataKHR` in the raytraced triangle example to prevent a validation error. By @Vecvec in [#6282](https://github.com/gfx-rs/wgpu/pull/6282) ### Changes +- `wgpu_hal::gles::Adapter::new_external` now requires the context to be current when dropping the adapter and related objects. By @Imberflur in [#6114](https://github.com/gfx-rs/wgpu/pull/6114). - Reduce the amount of debug and trace logs emitted by wgpu-core and wgpu-hal. By @nical in [#6065](https://github.com/gfx-rs/wgpu/issues/6065) -- `Rg11b10Float` is renamed to `Rg11b10UFloat`. By @sagudev in [#6108](https://github.com/gfx-rs/wgpu/pull/6108) +- `Rg11b10Float` is renamed to `Rg11b10Ufloat`. By @sagudev in [#6108](https://github.com/gfx-rs/wgpu/pull/6108) + +#### HAL + +- Change the inconsistent `DropGuard` based API on Vulkan and GLES to a consistent, callback-based one. By @jerzywilczek in [#6164](https://github.com/gfx-rs/wgpu/pull/6164) + +### Documentation + +- Removed some OpenGL and Vulkan references from `wgpu-types` documentation. Fixed Storage texel types in examples. By @Nelarius in [#6271](https://github.com/gfx-rs/wgpu/pull/6271) ### Dependency Updates #### GLES - Replace `winapi` code in WGL wrapper to use the `windows` crate. By @MarijnS95 in [#6006](https://github.com/gfx-rs/wgpu/pull/6006) +- Update `glutin` to `0.31` with `glutin-winit` crate. By @MarijnS95 in [#6150](https://github.com/gfx-rs/wgpu/pull/6150) and [#6176](https://github.com/gfx-rs/wgpu/pull/6176) +- Implement `Adapter::new_external()` for WGL (just like EGL) to import an external OpenGL ES context. By @MarijnS95 in [#6152](https://github.com/gfx-rs/wgpu/pull/6152) + +#### DX12 + +- Replace `winapi` code to use the `windows` crate. By @MarijnS95 in [#5956](https://github.com/gfx-rs/wgpu/pull/5956) and [#6173](https://github.com/gfx-rs/wgpu/pull/6173) + +#### HAL + +- Update `parking_lot` to `0.12`. By @mahkoh in [#6287](https://github.com/gfx-rs/wgpu/pull/6287) ## 22.0.0 (2024-07-17) @@ -224,6 +287,7 @@ By @teoxoy in [#5901](https://github.com/gfx-rs/wgpu/pull/5901) - `MemoryHints::MemoryUsage` favors memory usage over performance. This hint is typically useful for smaller applications or UI libraries. - `MemoryHints::Manual` allows the user to specify parameters for the underlying GPU memory allocator. These parameters are subject to change. - These hints may be ignored by some backends. Currently only the Vulkan and D3D12 backends take them into account. +- Add `HTMLImageElement` and `ImageData` as external source for copying images. By @Valaphee in [#5668](https://github.com/gfx-rs/wgpu/pull/5668) #### Naga @@ -747,7 +811,7 @@ The easiest way to make this code safe is to use shared ownership: ```rust let window: Arc; // ... -let surface = instance.create_surface(my_window.clone())?; +let surface = instance.create_surface(window.clone())?; ``` All platform specific surface creation using points have moved into `SurfaceTargetUnsafe` as well. diff --git a/Cargo.lock b/Cargo.lock index 2f4d41739d..d946614c48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,9 +20,9 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] @@ -33,6 +33,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -75,10 +81,10 @@ dependencies = [ "jni-sys", "libc", "log", - "ndk 0.8.0", + "ndk", "ndk-context", - "ndk-sys 0.5.0+25.2.9519653", - "num_enum 0.7.2", + "ndk-sys", + "num_enum", "thiserror", ] @@ -154,9 +160,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arbitrary" @@ -186,7 +192,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -200,21 +206,15 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" - -[[package]] -name = "arrayvec" -version = "0.5.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" dependencies = [ "serde", ] @@ -231,18 +231,18 @@ version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "libloading 0.8.5", + "libloading", ] [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -259,17 +259,17 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.8.0", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -370,22 +370,22 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.16.3" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -396,23 +396,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - -[[package]] -name = "calloop" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" -dependencies = [ - "bitflags 1.3.2", - "log", - "nix 0.25.1", - "slotmap", - "thiserror", - "vec_map", -] +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "calloop" @@ -434,10 +420,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" dependencies = [ - "calloop 0.12.4", + "calloop", "rustix", "wayland-backend", - "wayland-client 0.31.2", + "wayland-client", ] [[package]] @@ -448,12 +434,13 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.10" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -512,9 +499,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.15" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -522,14 +509,14 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.1", + "strsim", ] [[package]] @@ -541,7 +528,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -550,61 +537,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - -[[package]] -name = "cocoa" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" -dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics 0.22.3", - "foreign-types 0.3.2", - "libc", - "objc", -] - -[[package]] -name = "cocoa" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" -dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics 0.23.2", - "foreign-types 0.5.0", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" -dependencies = [ - "bitflags 1.3.2", - "block", - "core-foundation", - "core-graphics-types", - "libc", - "objc", -] - [[package]] name = "codespan-reporting" version = "0.11.1" @@ -627,37 +559,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" -[[package]] -name = "com" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" -dependencies = [ - "com_macros", -] - -[[package]] -name = "com_macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" -dependencies = [ - "com_macros_support", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "com_macros_support" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "combine" version = "4.6.7" @@ -699,9 +600,9 @@ dependencies = [ [[package]] name = "const_panic" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b" +checksum = "7782af8f90fe69a4bb41e460abe1727d493403d8b2cc43201a3a3e906b24379f" [[package]] name = "convert_case" @@ -731,19 +632,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core-graphics" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", - "foreign-types 0.3.2", - "libc", -] - [[package]] name = "core-graphics" version = "0.23.2" @@ -753,7 +641,7 @@ dependencies = [ "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types 0.5.0", + "foreign-types", "libc", ] @@ -768,18 +656,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core-text" -version = "20.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" -dependencies = [ - "core-foundation", - "core-graphics 0.23.2", - "foreign-types 0.5.0", - "libc", -] - [[package]] name = "crc32fast" version = "1.4.2" @@ -850,29 +726,6 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" -[[package]] -name = "crossfont" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb5a3822b594afc99b503cc1859b94686d3c3efdd60507a28587dab80ee1071" -dependencies = [ - "cocoa 0.25.0", - "core-foundation", - "core-foundation-sys", - "core-graphics 0.23.2", - "core-text", - "dwrote", - "foreign-types 0.5.0", - "freetype-rs", - "libc", - "log", - "objc", - "once_cell", - "pkg-config", - "servo-fontconfig", - "winapi", -] - [[package]] name = "crunchy" version = "0.2.2" @@ -886,7 +739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -903,62 +756,12 @@ dependencies = [ "tokio", ] -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "cursor-icon" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" -[[package]] -name = "d3d12" -version = "22.0.0" -dependencies = [ - "bitflags 2.6.0", - "libloading 0.8.5", - "winapi", -] - -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.109", -] - [[package]] name = "data-encoding" version = "2.6.0" @@ -1002,7 +805,7 @@ dependencies = [ "futures", "libc", "log", - "memoffset 0.9.1", + "memoffset", "parking_lot", "pin-project", "serde", @@ -1033,7 +836,7 @@ dependencies = [ "quote", "strum", "strum_macros", - "syn 2.0.74", + "syn", "thiserror", ] @@ -1106,7 +909,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -1119,7 +922,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 2.0.74", + "syn", ] [[package]] @@ -1140,7 +943,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.5", + "libloading", ] [[package]] @@ -1158,20 +961,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" -[[package]] -name = "dwrote" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" -dependencies = [ - "lazy_static", - "libc", - "serde", - "serde_derive", - "winapi", - "wio", -] - [[package]] name = "either" version = "1.13.0" @@ -1207,7 +996,7 @@ checksum = "b36f2ddfca91251bed7f931f24b192e4eaf0a0e0fa70cf81cfb1416a1973620e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -1258,21 +1047,11 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "expat-sys" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" -dependencies = [ - "cmake", - "pkg-config", -] - [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdeflate" @@ -1300,12 +1079,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -1320,21 +1099,6 @@ dependencies = [ "spin", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - [[package]] name = "foreign-types" version = "0.5.0" @@ -1342,7 +1106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared 0.3.1", + "foreign-types-shared", ] [[package]] @@ -1353,15 +1117,9 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -1377,28 +1135,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "freetype-rs" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb" -dependencies = [ - "bitflags 1.3.2", - "freetype-sys", - "libc", -] - -[[package]] -name = "freetype-sys" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" -dependencies = [ - "cmake", - "libc", - "pkg-config", -] - [[package]] name = "fslock" version = "0.2.1" @@ -1478,7 +1214,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -1513,9 +1249,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "979f00864edc7516466d6b3157706e06c032f22715700ddd878228a91d02bc56" +checksum = "dbb949699c3e4df3a183b1d2142cb24277057055ed23c68ed58894f76c517223" dependencies = [ "cfg-if", "libc", @@ -1549,9 +1285,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "gl_generator" @@ -1572,9 +1308,9 @@ checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" [[package]] name = "glow" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f865cbd94bd355b89611211e49508da98a1fce0ad755c1e8448fb96711b24528" +checksum = "2f4a888dbe8181a7535853469c21c67ca9a1cea9460b16808fc018ea9e55d248" dependencies = [ "js-sys", "slotmap", @@ -1584,65 +1320,54 @@ dependencies = [ [[package]] name = "glutin" -version = "0.29.1" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444c9ad294fdcaf20ccf6726b78f380b5450275540c9b68ab62f49726ad1c713" +checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" dependencies = [ + "bitflags 2.6.0", + "cfg_aliases", "cgl", - "cocoa 0.24.1", "core-foundation", + "dispatch", "glutin_egl_sys", - "glutin_gles2_sys", - "glutin_glx_sys", - "glutin_wgl_sys 0.1.5", - "libloading 0.7.4", - "log", - "objc", + "glutin_wgl_sys 0.5.0", + "icrate", + "libloading", + "objc2", "once_cell", - "osmesa-sys", - "parking_lot", "raw-window-handle 0.5.2", - "wayland-client 0.29.5", - "wayland-egl", - "winapi", - "winit 0.27.5", -] - -[[package]] -name = "glutin_egl_sys" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68900f84b471f31ea1d1355567eb865a2cf446294f06cef8d653ed7bcf5f013d" -dependencies = [ - "gl_generator", - "winapi", + "wayland-sys", + "windows-sys 0.48.0", + "x11-dl", ] [[package]] -name = "glutin_gles2_sys" -version = "0.1.5" +name = "glutin-winit" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103" +checksum = "1ebcdfba24f73b8412c5181e56f092b5eff16671c514ce896b258a0a64bd7735" dependencies = [ - "gl_generator", - "objc", + "cfg_aliases", + "glutin", + "raw-window-handle 0.5.2", + "winit", ] [[package]] -name = "glutin_glx_sys" -version = "0.1.8" +name = "glutin_egl_sys" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93d0575865098580c5b3a423188cd959419912ea60b1e48e8b3b526f6d02468" +checksum = "77cc5623f5309ef433c3dd4ca1223195347fe62c413da8e2fdd0eb76db2d9bcd" dependencies = [ "gl_generator", - "x11-dl", + "windows-sys 0.48.0", ] [[package]] name = "glutin_wgl_sys" -version = "0.1.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" dependencies = [ "gl_generator", ] @@ -1684,7 +1409,6 @@ dependencies = [ "log", "presser", "thiserror", - "winapi", "windows", ] @@ -1737,21 +1461,6 @@ dependencies = [ "allocator-api2", ] -[[package]] -name = "hassle-rs" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" -dependencies = [ - "bitflags 2.6.0", - "com", - "libc", - "libloading 0.8.5", - "thiserror", - "widestring", - "winapi", -] - [[package]] name = "heck" version = "0.4.1" @@ -1816,12 +1525,6 @@ dependencies = [ "objc2", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "0.5.0" @@ -1853,9 +1556,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "arbitrary", "equivalent", @@ -1863,25 +1566,13 @@ dependencies = [ "serde", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] @@ -1940,9 +1631,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1954,7 +1645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.8.5", + "libloading", "pkg-config", ] @@ -1981,9 +1672,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libfuzzer-sys" @@ -1996,16 +1687,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.8.5" @@ -2050,6 +1731,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" +[[package]] +name = "lock-analyzer" +version = "22.0.0" +dependencies = [ + "anyhow", + "ron", + "serde", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -2105,31 +1795,13 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] - -[[package]] -name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.9.1" @@ -2148,12 +1820,22 @@ dependencies = [ "bitflags 2.6.0", "block", "core-graphics-types", - "foreign-types 0.5.0", + "foreign-types", "log", "objc", "paste", ] +[[package]] +name = "minicov" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -2165,22 +1847,19 @@ dependencies = [ ] [[package]] -name = "mio" -version = "0.8.11" +name = "miniz_oxide" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.48.0", + "adler2", ] [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", @@ -2193,7 +1872,7 @@ name = "naga" version = "22.0.0" dependencies = [ "arbitrary", - "arrayvec 0.7.4", + "arrayvec", "bit-set", "bitflags 2.6.0", "cfg_aliases", @@ -2203,6 +1882,7 @@ dependencies = [ "hexf-parse", "hlsl-snapshots", "indexmap", + "itertools", "log", "petgraph", "pp-rs", @@ -2261,20 +1941,6 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e943b2c21337b7e3ec6678500687cdc741b7639ad457f234693352075c082204" -[[package]] -name = "ndk" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" -dependencies = [ - "bitflags 1.3.2", - "jni-sys", - "ndk-sys 0.4.1+23.1.7779620", - "num_enum 0.5.11", - "raw-window-handle 0.5.2", - "thiserror", -] - [[package]] name = "ndk" version = "0.8.0" @@ -2284,8 +1950,9 @@ dependencies = [ "bitflags 2.6.0", "jni-sys", "log", - "ndk-sys 0.5.0+25.2.9519653", - "num_enum 0.7.2", + "ndk-sys", + "num_enum", + "raw-window-handle 0.5.2", "raw-window-handle 0.6.2", "thiserror", ] @@ -2296,44 +1963,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" -[[package]] -name = "ndk-glue" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f" -dependencies = [ - "libc", - "log", - "ndk 0.7.0", - "ndk-context", - "ndk-macro", - "ndk-sys 0.4.1+23.1.7779620", - "once_cell", - "parking_lot", -] - -[[package]] -name = "ndk-macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" -dependencies = [ - "darling", - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ndk-sys" -version = "0.4.1+23.1.7779620" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" -dependencies = [ - "jni-sys", -] - [[package]] name = "ndk-sys" version = "0.5.0+25.2.9519653" @@ -2343,31 +1972,6 @@ dependencies = [ "jni-sys", ] -[[package]] -name = "nix" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.6.5", -] - -[[package]] -name = "nix" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.6.5", -] - [[package]] name = "noise" version = "0.8.2" @@ -2428,45 +2032,24 @@ dependencies = [ ] [[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive 0.5.11", -] - -[[package]] -name = "num_enum" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" -dependencies = [ - "num_enum_derive 0.7.2", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.11" +name = "num_enum" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", + "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -2526,9 +2109,9 @@ checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -2554,15 +2137,6 @@ dependencies = [ "libredox", ] -[[package]] -name = "osmesa-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" -dependencies = [ - "shared_library", -] - [[package]] name = "outref" version = "0.1.0" @@ -2592,9 +2166,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2667,7 +2241,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -2699,14 +2273,14 @@ dependencies = [ "serde", "wgpu-core", "wgpu-types", - "winit 0.29.15", + "winit", ] [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -2717,15 +2291,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -2740,7 +2314,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.7.4", ] [[package]] @@ -2781,21 +2355,11 @@ checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" [[package]] name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] @@ -2806,7 +2370,7 @@ checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" dependencies = [ "proc-macro-rules-macros", "proc-macro2", - "syn 2.0.74", + "syn", ] [[package]] @@ -2818,7 +2382,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -2838,18 +2402,18 @@ checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" [[package]] name = "quick-xml" -version = "0.31.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +checksum = "96a05e2e8efddfa51a84ca47cec303fac86c8541b686d37cac5efc0e094417bc" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2884,15 +2448,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" -[[package]] -name = "raw-window-handle" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" -dependencies = [ - "cty", -] - [[package]] name = "raw-window-handle" version = "0.5.2" @@ -3055,9 +2610,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -3078,15 +2633,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "safe_arch" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05" -dependencies = [ - "bytemuck", -] - [[package]] name = "same-file" version = "1.0.6" @@ -3110,27 +2656,15 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61270629cc6b4d77ec1907db1033d5c2e1a404c412743621981a871dc9c12339" -dependencies = [ - "crossfont", - "log", - "smithay-client-toolkit 0.16.1", - "tiny-skia 0.7.0", -] - -[[package]] -name = "sctk-adwaita" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" dependencies = [ "ab_glyph", "log", - "memmap2 0.9.4", - "smithay-client-toolkit 0.18.1", - "tiny-skia 0.11.4", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", ] [[package]] @@ -3156,29 +2690,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.206" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.206" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] name = "serde_json" -version = "1.0.124" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "indexmap", "itoa", @@ -3201,27 +2735,6 @@ dependencies = [ "v8", ] -[[package]] -name = "servo-fontconfig" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c" -dependencies = [ - "libc", - "servo-fontconfig-sys", -] - -[[package]] -name = "servo-fontconfig-sys" -version = "5.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388" -dependencies = [ - "expat-sys", - "freetype-sys", - "pkg-config", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -3232,14 +2745,10 @@ dependencies = [ ] [[package]] -name = "shared_library" -version = "0.1.9" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" -dependencies = [ - "lazy_static", - "libc", -] +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" @@ -3289,25 +2798,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "smithay-client-toolkit" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9" -dependencies = [ - "bitflags 1.3.2", - "calloop 0.10.6", - "dlib", - "lazy_static", - "log", - "memmap2 0.5.10", - "nix 0.24.3", - "pkg-config", - "wayland-client 0.29.5", - "wayland-cursor 0.29.5", - "wayland-protocols 0.29.5", -] - [[package]] name = "smithay-client-toolkit" version = "0.18.1" @@ -3315,21 +2805,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ "bitflags 2.6.0", - "calloop 0.12.4", + "calloop", "calloop-wayland-source", "cursor-icon", "libc", "log", - "memmap2 0.9.4", + "memmap2", "rustix", "thiserror", "wayland-backend", - "wayland-client 0.31.2", + "wayland-client", "wayland-csd-frame", - "wayland-cursor 0.31.1", - "wayland-protocols 0.31.2", + "wayland-cursor", + "wayland-protocols", "wayland-protocols-wlr", - "wayland-scanner 0.31.1", + "wayland-scanner", "xkeysym", ] @@ -3408,12 +2898,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" @@ -3439,25 +2923,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.74", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "syn", ] [[package]] name = "syn" -version = "2.0.74" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -3490,7 +2963,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -3522,21 +2995,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "tiny-skia" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642680569bb895b16e4b9d181c60be1ed136fa0c9c7f11d004daf053ba89bf82" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "bytemuck", - "cfg-if", - "png", - "safe_arch", - "tiny-skia-path 0.7.0", -] - [[package]] name = "tiny-skia" version = "0.11.4" @@ -3544,21 +3002,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec", "bytemuck", "cfg-if", "log", - "tiny-skia-path 0.11.4", -] - -[[package]] -name = "tiny-skia-path" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c114d32f0c2ee43d585367cb013dfaba967ab9f62b90d9af0d696e955e70fa6c" -dependencies = [ - "arrayref", - "bytemuck", + "tiny-skia-path", ] [[package]] @@ -3599,14 +3047,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.1", + "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -3623,7 +3071,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -3634,20 +3082,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.21.1" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ "indexmap", "toml_datetime", @@ -3705,9 +3142,9 @@ dependencies = [ [[package]] name = "tracy-client" -version = "0.17.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63de1e1d4115534008d8fd5788b39324d6f58fc707849090533828619351d855" +checksum = "373db47331c3407b343538df77eea2516884a0b126cdfb4b135acfd400015dd7" dependencies = [ "loom", "once_cell", @@ -3716,9 +3153,9 @@ dependencies = [ [[package]] name = "tracy-client-sys" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98b98232a2447ce0a58f9a0bfb5f5e39647b5c597c994b63945fcccd1306fafb" +checksum = "49cf0064dcb31c99aa1244c1b93439359e53f72ed217eef5db50abd442241e9a" dependencies = [ "cc", ] @@ -3784,24 +3221,24 @@ checksum = "bc3882f69607a2ac8cc4de3ee7993d8f68bb06f2974271195065b3bd07f2edea" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" @@ -3811,9 +3248,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "url" @@ -3866,7 +3303,7 @@ dependencies = [ "fslock", "gzip-header", "home", - "miniz_oxide", + "miniz_oxide 0.7.4", "once_cell", "which", ] @@ -3877,12 +3314,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.5" @@ -3913,34 +3344,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -3950,9 +3382,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3960,31 +3392,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-bindgen-test" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" +checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" dependencies = [ "console_error_panic_hook", "js-sys", + "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -3993,67 +3426,39 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" +checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] name = "wayland-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" dependencies = [ "cc", "downcast-rs", "rustix", "scoped-tls", "smallvec", - "wayland-sys 0.31.4", -] - -[[package]] -name = "wayland-client" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" -dependencies = [ - "bitflags 1.3.2", - "downcast-rs", - "libc", - "nix 0.24.3", - "scoped-tls", - "wayland-commons", - "wayland-scanner 0.29.5", - "wayland-sys 0.29.5", + "wayland-sys", ] [[package]] name = "wayland-client" -version = "0.31.2" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" +checksum = "e3f45d1222915ef1fd2057220c1d9d9624b7654443ea35c3877f7a52bd0a5a2d" dependencies = [ "bitflags 2.6.0", "rustix", "wayland-backend", - "wayland-scanner 0.31.1", -] - -[[package]] -name = "wayland-commons" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" -dependencies = [ - "nix 0.24.3", - "once_cell", - "smallvec", - "wayland-sys 0.29.5", + "wayland-scanner", ] [[package]] @@ -4069,48 +3474,15 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" -dependencies = [ - "nix 0.24.3", - "wayland-client 0.29.5", - "xcursor", -] - -[[package]] -name = "wayland-cursor" -version = "0.31.1" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba" +checksum = "3a94697e66e76c85923b0d28a0c251e8f0666f58fc47d316c0f4da6da75d37cb" dependencies = [ "rustix", - "wayland-client 0.31.2", + "wayland-client", "xcursor", ] -[[package]] -name = "wayland-egl" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402de949f81a012926d821a2d659f930694257e76dd92b6e0042ceb27be4107d" -dependencies = [ - "wayland-client 0.29.5", - "wayland-sys 0.29.5", -] - -[[package]] -name = "wayland-protocols" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" -dependencies = [ - "bitflags 1.3.2", - "wayland-client 0.29.5", - "wayland-commons", - "wayland-scanner 0.29.5", -] - [[package]] name = "wayland-protocols" version = "0.31.2" @@ -4119,8 +3491,8 @@ checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ "bitflags 2.6.0", "wayland-backend", - "wayland-client 0.31.2", - "wayland-scanner 0.31.1", + "wayland-client", + "wayland-scanner", ] [[package]] @@ -4131,9 +3503,9 @@ checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ "bitflags 2.6.0", "wayland-backend", - "wayland-client 0.31.2", - "wayland-protocols 0.31.2", - "wayland-scanner 0.31.1", + "wayland-client", + "wayland-protocols", + "wayland-scanner", ] [[package]] @@ -4144,27 +3516,16 @@ checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ "bitflags 2.6.0", "wayland-backend", - "wayland-client 0.31.2", - "wayland-protocols 0.31.2", - "wayland-scanner 0.31.1", -] - -[[package]] -name = "wayland-scanner" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" -dependencies = [ - "proc-macro2", - "quote", - "xml-rs", + "wayland-client", + "wayland-protocols", + "wayland-scanner", ] [[package]] name = "wayland-scanner" -version = "0.31.1" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" dependencies = [ "proc-macro2", "quick-xml", @@ -4173,20 +3534,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" -dependencies = [ - "dlib", - "lazy_static", - "pkg-config", -] - -[[package]] -name = "wayland-sys" -version = "0.31.4" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" dependencies = [ "dlib", "log", @@ -4196,9 +3546,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -4218,7 +3568,7 @@ dependencies = [ name = "wgpu" version = "22.0.0" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "cfg_aliases", "document-features", "js-sys", @@ -4259,7 +3609,7 @@ dependencies = [ name = "wgpu-core" version = "22.0.0" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "bit-vec", "bitflags 2.6.0", "bytemuck", @@ -4309,7 +3659,7 @@ dependencies = [ "web-time", "wgpu", "wgpu-test", - "winit 0.29.15", + "winit", ] [[package]] @@ -4317,7 +3667,7 @@ name = "wgpu-hal" version = "22.0.0" dependencies = [ "android_system_properties", - "arrayvec 0.7.4", + "arrayvec", "ash", "bit-set", "bitflags 2.6.0", @@ -4325,29 +3675,29 @@ dependencies = [ "cfg-if", "cfg_aliases", "core-graphics-types", - "d3d12", "env_logger", "glam", "glow", "glutin", + "glutin-winit", "glutin_wgl_sys 0.6.0", "gpu-alloc", "gpu-allocator", "gpu-descriptor", - "hassle-rs", "js-sys", "khronos-egl", "libc", - "libloading 0.8.5", + "libloading", "log", "metal", "naga", - "ndk-sys 0.5.0+25.2.9519653", + "ndk-sys", "objc", "once_cell", "parking_lot", "profiling", "range-alloc", + "raw-window-handle 0.5.2", "raw-window-handle 0.6.2", "renderdoc-sys", "rustc-hash", @@ -4356,9 +3706,9 @@ dependencies = [ "wasm-bindgen", "web-sys", "wgpu-types", - "winapi", "windows", - "winit 0.29.15", + "windows-core", + "winit", ] [[package]] @@ -4380,7 +3730,7 @@ version = "22.0.0" dependencies = [ "heck 0.5.0", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -4388,7 +3738,7 @@ name = "wgpu-test" version = "22.0.0" dependencies = [ "anyhow", - "arrayvec 0.7.4", + "arrayvec", "bitflags 2.6.0", "bytemuck", "cfg-if", @@ -4443,12 +3793,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "widestring" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" - [[package]] name = "winapi" version = "0.3.9" @@ -4471,7 +3815,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -4511,7 +3855,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -4522,7 +3866,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] [[package]] @@ -4544,19 +3888,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -4657,12 +3988,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -4681,12 +4006,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -4711,12 +4030,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -4735,12 +4048,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -4777,12 +4084,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -4801,39 +4102,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winit" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb796d6fbd86b2fd896c9471e6f04d39d750076ebe5680a3958f00f5ab97657c" -dependencies = [ - "bitflags 1.3.2", - "cocoa 0.24.1", - "core-foundation", - "core-graphics 0.22.3", - "dispatch", - "instant", - "libc", - "log", - "mio 0.8.11", - "ndk 0.7.0", - "ndk-glue", - "objc", - "once_cell", - "parking_lot", - "percent-encoding", - "raw-window-handle 0.4.3", - "raw-window-handle 0.5.2", - "sctk-adwaita 0.4.3", - "smithay-client-toolkit 0.16.1", - "wasm-bindgen", - "wayland-client 0.29.5", - "wayland-protocols 0.29.5", - "web-sys", - "windows-sys 0.36.1", - "x11-dl", -] - [[package]] name = "winit" version = "0.29.15" @@ -4845,34 +4113,35 @@ dependencies = [ "atomic-waker", "bitflags 2.6.0", "bytemuck", - "calloop 0.12.4", + "calloop", "cfg_aliases", "core-foundation", - "core-graphics 0.23.2", + "core-graphics", "cursor-icon", "icrate", "js-sys", "libc", "log", - "memmap2 0.9.4", - "ndk 0.8.0", - "ndk-sys 0.5.0+25.2.9519653", + "memmap2", + "ndk", + "ndk-sys", "objc2", "once_cell", "orbclient", "percent-encoding", + "raw-window-handle 0.5.2", "raw-window-handle 0.6.2", "redox_syscall 0.3.5", "rustix", - "sctk-adwaita 0.8.1", - "smithay-client-toolkit 0.18.1", + "sctk-adwaita", + "smithay-client-toolkit", "smol_str", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", "wayland-backend", - "wayland-client 0.31.2", - "wayland-protocols 0.31.2", + "wayland-client", + "wayland-protocols", "wayland-protocols-plasma", "web-sys", "web-time", @@ -4884,22 +4153,13 @@ dependencies = [ [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] -[[package]] -name = "wio" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" -dependencies = [ - "winapi", -] - [[package]] name = "x11-dl" version = "2.21.0" @@ -4920,7 +4180,7 @@ dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "libloading 0.8.5", + "libloading", "once_cell", "rustix", "x11rb-protocol", @@ -4934,9 +4194,9 @@ checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f513f231f0810b04d988f0df4fb16ef0b6b25d23248f2c4b56b074e6b1b0ffe4" +checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" [[package]] name = "xkbcommon-dl" @@ -4959,9 +4219,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" [[package]] name = "zerocopy" @@ -4980,5 +4240,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 04b26b8044..da5ecbd37d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,8 @@ members = [ # default members "benches", - "d3d12", "examples", + "lock-analyzer", "naga-cli", "naga", "naga/fuzz", @@ -24,8 +24,8 @@ members = [ exclude = [] default-members = [ "benches", - "d3d12", "examples", + "lock-analyzer", "naga-cli", "naga", "naga/fuzz", @@ -70,13 +70,13 @@ path = "./naga" version = "22.0.0" [workspace.dependencies] -anyhow = "1.0.86" +anyhow = "1.0.89" argh = "0.1.5" arrayvec = "0.7" bincode = "1" bit-vec = "0.8" bitflags = "2.6" -bytemuck = { version = "1.16", features = ["derive"] } +bytemuck = { version = "1.18", features = ["derive"] } cfg_aliases = "0.1" cfg-if = "1" criterion = "0.5" @@ -96,8 +96,7 @@ indexmap = "2" itertools = { version = "0.10.5" } ktx2 = "0.3" libc = "0.2" -# libloading 0.8 switches from `winapi` to `windows-sys`; permit either -libloading = ">=0.7, <0.9" +libloading = "0.8" libtest-mimic = "0.6" log = "0.4" nanorand = { version = "0.7", default-features = false, features = ["wyrand"] } @@ -106,7 +105,7 @@ noise = { version = "0.8", git = "https://github.com/Razaekel/noise-rs.git", rev nv-flip = "0.1" obj = "0.10" once_cell = "1.19.0" -parking_lot = ">=0.11, <0.13" # parking_lot 0.12 switches from `winapi` to `windows`; permit either +parking_lot = "0.12.1" pico-args = { version = "0.5.0", features = [ "eq-separator", "short-space-opt", @@ -121,7 +120,7 @@ renderdoc-sys = "1.1.0" ron = "0.8" rustc-hash = "1.1.0" serde = "1" -serde_json = "1.0.124" +serde_json = "1.0.128" smallvec = "1" static_assertions = "1.1.0" strum = { version = "0.25.0", features = ["derive"] } @@ -148,19 +147,15 @@ gpu-descriptor = "0.3" # DX dependencies bit-set = "0.8" -gpu-allocator = { version = "0.27", default-features = false, features = [ - "d3d12", - "public-winapi", -] } -d3d12 = { version = "22.0.0", path = "./d3d12/" } +gpu-allocator = { version = "0.27", default-features = false } range-alloc = "0.1" -winapi = "0.3" -hassle-rs = "0.11.0" +windows-core = { version = "0.58", default-features = false } # Gles dependencies khronos-egl = "6" -glow = "0.14.0" -glutin = "0.29.1" +glow = "0.14.1" +glutin = { version = "0.31", default-features = false } +glutin-winit = { version = "0.4", default-features = false } glutin_wgl_sys = "0.6" # DX and GLES dependencies @@ -169,11 +164,11 @@ windows = { version = "0.58", default-features = false } # wasm32 dependencies console_error_panic_hook = "0.1.7" console_log = "1" -js-sys = "0.3.69" +js-sys = "0.3.70" wasm-bindgen = "0.2.87" -wasm-bindgen-futures = "0.4.42" +wasm-bindgen-futures = "0.4.43" wasm-bindgen-test = "0.3" -web-sys = "0.3.69" +web-sys = "0.3.70" web-time = "0.2.4" # deno dependencies @@ -183,7 +178,7 @@ deno_url = "0.143.0" deno_web = "0.174.0" deno_webidl = "0.143.0" deno_webgpu = { version = "0.118.0", path = "./deno_webgpu" } -tokio = "1.39.2" +tokio = "1.40.0" termcolor = "1.4.1" # android dependencies diff --git a/benches/benches/computepass.rs b/benches/benches/computepass.rs index 2af1413605..719f84696e 100644 --- a/benches/benches/computepass.rs +++ b/benches/benches/computepass.rs @@ -389,7 +389,7 @@ impl ComputepassState { let end_idx = start_idx + dispatch_per_pass; for dispatch_idx in start_idx..end_idx { compute_pass.set_pipeline(&self.pipeline); - compute_pass.set_bind_group(0, &self.bind_groups[dispatch_idx], &[]); + compute_pass.set_bind_group(0, Some(&self.bind_groups[dispatch_idx]), &[]); compute_pass.dispatch_workgroups(1, 1, 1); } @@ -412,7 +412,7 @@ impl ComputepassState { }); compute_pass.set_pipeline(self.bindless_pipeline.as_ref().unwrap()); - compute_pass.set_bind_group(0, self.bindless_bind_group.as_ref().unwrap(), &[]); + compute_pass.set_bind_group(0, Some(self.bindless_bind_group.as_ref().unwrap()), &[]); for _ in 0..dispatch_count_bindless { compute_pass.dispatch_workgroups(1, 1, 1); } @@ -447,7 +447,7 @@ fn run_bench(ctx: &mut Criterion) { }; group.bench_function( - &format!("{cpasses} computepasses x {dispatch_per_pass} dispatches ({label})"), + format!("{cpasses} computepasses x {dispatch_per_pass} dispatches ({label})"), |b| { Lazy::force(&state); @@ -496,7 +496,7 @@ fn run_bench(ctx: &mut Criterion) { for threads in [2, 4, 8] { let dispatch_per_pass = dispatch_count / threads; group.bench_function( - &format!("{threads} threads x {dispatch_per_pass} dispatch"), + format!("{threads} threads x {dispatch_per_pass} dispatch"), |b| { Lazy::force(&state); @@ -537,7 +537,7 @@ fn run_bench(ctx: &mut Criterion) { let mut group = ctx.benchmark_group("Computepass: Bindless"); group.throughput(Throughput::Elements(dispatch_count_bindless as _)); - group.bench_function(&format!("{dispatch_count_bindless} dispatch"), |b| { + group.bench_function(format!("{dispatch_count_bindless} dispatch"), |b| { Lazy::force(&state); b.iter_custom(|iters| { diff --git a/benches/benches/renderpass.rs b/benches/benches/renderpass.rs index 7f2e14116e..fe23aa62be 100644 --- a/benches/benches/renderpass.rs +++ b/benches/benches/renderpass.rs @@ -367,7 +367,7 @@ impl RenderpassState { let end_idx = start_idx + draws_per_pass; for draw_idx in start_idx..end_idx { render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &self.bind_groups[draw_idx], &[]); + render_pass.set_bind_group(0, Some(&self.bind_groups[draw_idx]), &[]); for i in 0..VERTEX_BUFFERS_PER_DRAW { render_pass.set_vertex_buffer( i as u32, @@ -410,7 +410,7 @@ impl RenderpassState { }); render_pass.set_pipeline(self.bindless_pipeline.as_ref().unwrap()); - render_pass.set_bind_group(0, self.bindless_bind_group.as_ref().unwrap(), &[]); + render_pass.set_bind_group(0, Some(self.bindless_bind_group.as_ref().unwrap()), &[]); for i in 0..VERTEX_BUFFERS_PER_DRAW { render_pass.set_vertex_buffer(i as u32, self.vertex_buffers[0].slice(..)); } @@ -448,7 +448,7 @@ fn run_bench(ctx: &mut Criterion) { }; group.bench_function( - &format!("{rpasses} renderpasses x {draws_per_pass} draws ({label})"), + format!("{rpasses} renderpasses x {draws_per_pass} draws ({label})"), |b| { Lazy::force(&state); @@ -501,41 +501,38 @@ fn run_bench(ctx: &mut Criterion) { for threads in [2, 4, 8] { let draws_per_pass = draw_count / threads; - group.bench_function( - &format!("{threads} threads x {draws_per_pass} draws"), - |b| { - Lazy::force(&state); + group.bench_function(format!("{threads} threads x {draws_per_pass} draws"), |b| { + Lazy::force(&state); - b.iter_custom(|iters| { - profiling::scope!("benchmark invocation"); + b.iter_custom(|iters| { + profiling::scope!("benchmark invocation"); - // This benchmark hangs on Apple Paravirtualized GPUs. No idea why. - if state.device_state.adapter_info.name.contains("Paravirtual") { - return Duration::from_secs_f32(1.0); - } + // This benchmark hangs on Apple Paravirtualized GPUs. No idea why. + if state.device_state.adapter_info.name.contains("Paravirtual") { + return Duration::from_secs_f32(1.0); + } - let mut duration = Duration::ZERO; + let mut duration = Duration::ZERO; - for _ in 0..iters { - profiling::scope!("benchmark iteration"); + for _ in 0..iters { + profiling::scope!("benchmark iteration"); - let start = Instant::now(); + let start = Instant::now(); - let buffers = (0..threads) - .into_par_iter() - .map(|i| state.run_subpass(i, threads, draw_count)) - .collect::>(); + let buffers = (0..threads) + .into_par_iter() + .map(|i| state.run_subpass(i, threads, draw_count)) + .collect::>(); - duration += start.elapsed(); + duration += start.elapsed(); - state.device_state.queue.submit(buffers); - state.device_state.device.poll(wgpu::Maintain::Wait); - } + state.device_state.queue.submit(buffers); + state.device_state.device.poll(wgpu::Maintain::Wait); + } - duration - }) - }, - ); + duration + }) + }); } group.finish(); @@ -543,7 +540,7 @@ fn run_bench(ctx: &mut Criterion) { let mut group = ctx.benchmark_group("Renderpass: Bindless"); group.throughput(Throughput::Elements(draw_count as _)); - group.bench_function(&format!("{draw_count} draws"), |b| { + group.bench_function(format!("{draw_count} draws"), |b| { Lazy::force(&state); b.iter_custom(|iters| { diff --git a/benches/benches/resource_creation.rs b/benches/benches/resource_creation.rs index c23f132bbe..da0c79a406 100644 --- a/benches/benches/resource_creation.rs +++ b/benches/benches/resource_creation.rs @@ -17,7 +17,7 @@ fn run_bench(ctx: &mut Criterion) { for threads in [1, 2, 4, 8] { let resources_per_thread = RESOURCES_TO_CREATE / threads; group.bench_function( - &format!("{threads} threads x {resources_per_thread} resource"), + format!("{threads} threads x {resources_per_thread} resource"), |b| { Lazy::force(&state); diff --git a/d3d12/CHANGELOG.md b/d3d12/CHANGELOG.md deleted file mode 100644 index 6af566ae68..0000000000 --- a/d3d12/CHANGELOG.md +++ /dev/null @@ -1,32 +0,0 @@ -# Change Log - -## v0.6.0 (2023-01-25) - - add helpers for IDXGIFactoryMedia - - add `create_swapchain_for_composition_surface_handle` - -## v0.5.0 (2022-07-01) - - add COM helpers - - enable D3D11 adapter use - -## v0.4.1 (2021-08-18) - - expose all indirect argument types - - expose methods for setting root constants - -## v0.4.0 (2021-04-29) - - update `libloading` to 0.7 - -## v0.3.1 (2020-07-07) - - create shader from IL - - fix default doc target - - debug impl for root descriptors - -## v0.3.0 (2019-11-01) - - resource transitions - - dynamic library loading - -## v0.2.2 (2019-10-04) - - add `D3DHeap` - - add root descriptor - -## v0.1.0 (2018-12-26) - - basic version diff --git a/d3d12/Cargo.toml b/d3d12/Cargo.toml deleted file mode 100644 index a792aeab69..0000000000 --- a/d3d12/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -name = "d3d12" -version = "22.0.0" -authors = ["gfx-rs developers"] -description = "Low level D3D12 API wrapper" -repository = "https://github.com/gfx-rs/wgpu/tree/trunk/d3d12" -keywords = ["windows", "graphics"] -license = "MIT OR Apache-2.0" -documentation = "https://docs.rs/d3d12" -categories = [ - "api-bindings", - "graphics", - "memory-management", - "os::windows-apis", -] -edition = "2018" - -[features] -implicit-link = [] - -[target.'cfg(windows)'.dependencies] -bitflags = "2" -# libloading 0.8 switches from `winapi` to `windows-sys`; permit either -libloading = { version = ">=0.7, <0.9", optional = true } - -[target.'cfg(windows)'.dependencies.winapi] -version = "0.3" -features = [ - "dxgi1_2", - "dxgi1_3", - "dxgi1_4", - "dxgi1_5", - "dxgi1_6", - "dxgidebug", - "d3d12", - "d3d12sdklayers", - "d3dcommon", - "d3dcompiler", - "dxgiformat", - "synchapi", - "winerror", -] - -[package.metadata.docs.rs] -targets = ["x86_64-pc-windows-msvc"] diff --git a/d3d12/README.md b/d3d12/README.md deleted file mode 100644 index 718bf73555..0000000000 --- a/d3d12/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# d3d12-rs -[![Crates.io](https://img.shields.io/crates/v/d3d12.svg)](https://crates.io/crates/d3d12) -[![Docs.rs](https://docs.rs/d3d12/badge.svg)](https://docs.rs/d3d12) - -Rust wrapper for raw D3D12 access. diff --git a/d3d12/src/com.rs b/d3d12/src/com.rs deleted file mode 100644 index 556495f612..0000000000 --- a/d3d12/src/com.rs +++ /dev/null @@ -1,263 +0,0 @@ -use crate::D3DResult; -use std::{ - fmt, - hash::{Hash, Hasher}, - ops::Deref, - ptr, -}; -use winapi::{ctypes::c_void, um::unknwnbase::IUnknown, Interface}; - -#[repr(transparent)] -pub struct ComPtr(*mut T); - -impl ComPtr { - pub fn null() -> Self { - ComPtr(ptr::null_mut()) - } - - pub unsafe fn from_raw(raw: *mut T) -> Self { - if !raw.is_null() { - (*(raw as *mut IUnknown)).AddRef(); - } - ComPtr(raw) - } - - pub fn is_null(&self) -> bool { - self.0.is_null() - } - - pub fn as_ptr(&self) -> *const T { - self.0 - } - - pub fn as_mut_ptr(&self) -> *mut T { - self.0 - } - - pub fn mut_void(&mut self) -> *mut *mut c_void { - &mut self.0 as *mut *mut _ as *mut *mut _ - } - - pub fn mut_self(&mut self) -> *mut *mut T { - &mut self.0 as *mut *mut _ - } -} - -impl ComPtr { - pub unsafe fn as_unknown(&self) -> &IUnknown { - debug_assert!(!self.is_null()); - &*(self.0 as *mut IUnknown) - } - - pub unsafe fn cast(&self) -> D3DResult> - where - U: Interface, - { - debug_assert!(!self.is_null()); - let mut obj = ComPtr::::null(); - let hr = self - .as_unknown() - .QueryInterface(&U::uuidof(), obj.mut_void()); - (obj, hr) - } -} - -impl Clone for ComPtr { - fn clone(&self) -> Self { - debug_assert!(!self.is_null()); - unsafe { - self.as_unknown().AddRef(); - } - ComPtr(self.0) - } -} - -impl Drop for ComPtr { - fn drop(&mut self) { - if !self.0.is_null() { - unsafe { - self.as_unknown().Release(); - } - } - } -} - -impl Deref for ComPtr { - type Target = T; - fn deref(&self) -> &T { - debug_assert!(!self.is_null()); - unsafe { &*self.0 } - } -} - -impl fmt::Debug for ComPtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ComPtr( ptr: {:?} )", self.0) - } -} - -impl PartialEq<*mut T> for ComPtr { - fn eq(&self, other: &*mut T) -> bool { - self.0 == *other - } -} - -impl PartialEq for ComPtr { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl Hash for ComPtr { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -/// Macro that allows generation of an easy to use enum for dealing with many different possible versions of a COM object. -/// -/// Give the variants so that parents come before children. This often manifests as going up in order (1 -> 2 -> 3). This is vital for safety. -/// -/// Three function names need to be attached to each variant. The examples are given for the MyComObject1 variant below: -/// - the from function (`ComPtr -> Self`) -/// - the as function (`&self -> Option>`) -/// - the unwrap function (`&self -> ComPtr` panicking on failure to cast) -/// -/// ```rust -/// # pub use d3d12::weak_com_inheritance_chain; -/// # mod actual { -/// # pub struct ComObject; impl winapi::Interface for ComObject { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } } -/// # pub struct ComObject1; impl winapi::Interface for ComObject1 { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } } -/// # pub struct ComObject2; impl winapi::Interface for ComObject2 { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } } -/// # } -/// weak_com_inheritance_chain! { -/// pub enum MyComObject { -/// MyComObject(actual::ComObject), from_my_com_object, as_my_com_object, my_com_object; // First variant doesn't use "unwrap" as it can never fail -/// MyComObject1(actual::ComObject1), from_my_com_object1, as_my_com_object1, unwrap_my_com_object1; -/// MyComObject2(actual::ComObject2), from_my_com_object2, as_my_com_object2, unwrap_my_com_object2; -/// } -/// } -/// ``` -#[macro_export] -macro_rules! weak_com_inheritance_chain { - // We first match a human readable enum style, before going into the recursive section. - // - // Internal calls to the macro have either the prefix - // - @recursion_logic for the recursion and termination - // - @render_members for the actual call to fill in the members. - ( - $(#[$meta:meta])* - $vis:vis enum $name:ident { - $first_variant:ident($first_type:ty), $first_from_name:ident, $first_as_name:ident, $first_unwrap_name:ident $(;)? - $($variant:ident($type:ty), $from_name:ident, $as_name:ident, $unwrap_name:ident);* $(;)? - } - ) => { - $(#[$meta])* - $vis enum $name { - $first_variant($crate::ComPtr<$first_type>), - $( - $variant($crate::ComPtr<$type>) - ),+ - } - impl $name { - $crate::weak_com_inheritance_chain! { - @recursion_logic, - $vis, - ; - $first_variant($first_type), $first_from_name, $first_as_name, $first_unwrap_name; - $($variant($type), $from_name, $as_name, $unwrap_name);* - } - } - - impl std::ops::Deref for $name { - type Target = $crate::ComPtr<$first_type>; - fn deref(&self) -> &Self::Target { - self.$first_unwrap_name() - } - } - }; - - // This is the iteration case of the recursion. We instantiate the member functions for the variant we - // are currently at, recursing on ourself for the next variant. Note we only keep track of the previous - // variant name, not the functions names, as those are not needed. - ( - @recursion_logic, - $vis:vis, - $(,)? $($prev_variant:ident),* $(,)?; - $this_variant:ident($this_type:ty), $this_from_name:ident, $this_as_name:ident, $this_unwrap_name:ident $(;)? - $($next_variant:ident($next_type:ty), $next_from_name:ident, $next_as_name:ident, $next_unwrap_name:ident);* - ) => { - // Actually generate the members for this variant. Needs the previous and future variant names. - $crate::weak_com_inheritance_chain! { - @render_members, - $vis, - $this_from_name, $this_as_name, $this_unwrap_name; - $($prev_variant),*; - $this_variant($this_type); - $($next_variant),*; - } - - // Recurse on ourselves. If there is no future variants left, we'll hit the base case as the final expansion returns no tokens. - $crate::weak_com_inheritance_chain! { - @recursion_logic, - $vis, - $($prev_variant),* , $this_variant; - $($next_variant($next_type), $next_from_name, $next_as_name, $next_unwrap_name);* - } - }; - // Base case for recursion. There are no more variants left - ( - @recursion_logic, - $vis:vis, - $($prev_variant:ident),*; - ) => {}; - - - // This is where we generate the members using the given names. - ( - @render_members, - $vis:vis, - $from_name:ident, $as_name:ident, $unwrap_name:ident; - $($prev_variant:ident),*; - $variant:ident($type:ty); - $($next_variant:ident),*; - ) => { - // Construct this enum from weak pointer to this interface. For best usability, always use the highest constructor you can. This doesn't try to upcast. - $vis unsafe fn $from_name(value: $crate::ComPtr<$type>) -> Self { - Self::$variant(value) - } - - // Returns Some if the value implements the interface otherwise returns None. - $vis fn $as_name(&self) -> Option<&$crate::ComPtr<$type>> { - match *self { - $( - Self::$prev_variant(_) => None, - )* - Self::$variant(ref v) => Some(v), - $( - Self::$next_variant(ref v) => { - // v is &ComPtr and se cast to &ComPtr - Some(unsafe { std::mem::transmute(v) }) - } - )* - } - } - - // Returns the interface if the value implements it, otherwise panics. - #[track_caller] - $vis fn $unwrap_name(&self) -> &$crate::ComPtr<$type> { - match *self { - $( - Self::$prev_variant(_) => panic!(concat!("Tried to unwrap a ", stringify!($prev_variant), " as a ", stringify!($variant))), - )* - Self::$variant(ref v) => &*v, - $( - Self::$next_variant(ref v) => { - // v is &ComPtr and se cast to &ComPtr - unsafe { std::mem::transmute(v) } - } - )* - } - } - }; -} diff --git a/d3d12/src/command_allocator.rs b/d3d12/src/command_allocator.rs deleted file mode 100644 index b50ec00d4a..0000000000 --- a/d3d12/src/command_allocator.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! Command Allocator - -use crate::com::ComPtr; -use winapi::um::d3d12; - -pub type CommandAllocator = ComPtr; - -impl CommandAllocator { - pub fn reset(&self) { - unsafe { - self.Reset(); - } - } -} diff --git a/d3d12/src/command_list.rs b/d3d12/src/command_list.rs deleted file mode 100644 index 1f8c0d53c2..0000000000 --- a/d3d12/src/command_list.rs +++ /dev/null @@ -1,406 +0,0 @@ -//! Graphics command list - -use crate::{ - com::ComPtr, resource::DiscardRegion, CommandAllocator, CpuDescriptor, DescriptorHeap, Format, - GpuAddress, GpuDescriptor, IndexCount, InstanceCount, PipelineState, Rect, Resource, RootIndex, - RootSignature, Subresource, VertexCount, VertexOffset, WorkGroupCount, HRESULT, -}; -use std::{mem, ptr}; -use winapi::um::d3d12; - -#[repr(u32)] -#[derive(Clone, Copy)] -pub enum CmdListType { - Direct = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT, - Bundle = d3d12::D3D12_COMMAND_LIST_TYPE_BUNDLE, - Compute = d3d12::D3D12_COMMAND_LIST_TYPE_COMPUTE, - Copy = d3d12::D3D12_COMMAND_LIST_TYPE_COPY, - // VideoDecode = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE, - // VideoProcess = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS, -} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct ClearFlags: u32 { - const DEPTH = d3d12::D3D12_CLEAR_FLAG_DEPTH; - const STENCIL = d3d12::D3D12_CLEAR_FLAG_STENCIL; - } -} - -#[repr(transparent)] -pub struct IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC); - -impl IndirectArgument { - pub fn draw() -> Self { - IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC { - Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, - ..unsafe { mem::zeroed() } - }) - } - - pub fn draw_indexed() -> Self { - IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC { - Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED, - ..unsafe { mem::zeroed() } - }) - } - - pub fn dispatch() -> Self { - IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC { - Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH, - ..unsafe { mem::zeroed() } - }) - } - - pub fn vertex_buffer(slot: u32) -> Self { - let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC { - Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW, - ..unsafe { mem::zeroed() } - }; - *unsafe { desc.u.VertexBuffer_mut() } = - d3d12::D3D12_INDIRECT_ARGUMENT_DESC_VertexBuffer { Slot: slot }; - IndirectArgument(desc) - } - - pub fn constant(root_index: RootIndex, dest_offset_words: u32, count: u32) -> Self { - let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC { - Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT, - ..unsafe { mem::zeroed() } - }; - *unsafe { desc.u.Constant_mut() } = d3d12::D3D12_INDIRECT_ARGUMENT_DESC_Constant { - RootParameterIndex: root_index, - DestOffsetIn32BitValues: dest_offset_words, - Num32BitValuesToSet: count, - }; - IndirectArgument(desc) - } - - pub fn constant_buffer_view(root_index: RootIndex) -> Self { - let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC { - Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW, - ..unsafe { mem::zeroed() } - }; - *unsafe { desc.u.ConstantBufferView_mut() } = - d3d12::D3D12_INDIRECT_ARGUMENT_DESC_ConstantBufferView { - RootParameterIndex: root_index, - }; - IndirectArgument(desc) - } - - pub fn shader_resource_view(root_index: RootIndex) -> Self { - let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC { - Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW, - ..unsafe { mem::zeroed() } - }; - *unsafe { desc.u.ShaderResourceView_mut() } = - d3d12::D3D12_INDIRECT_ARGUMENT_DESC_ShaderResourceView { - RootParameterIndex: root_index, - }; - IndirectArgument(desc) - } - - pub fn unordered_access_view(root_index: RootIndex) -> Self { - let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC { - Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW, - ..unsafe { mem::zeroed() } - }; - *unsafe { desc.u.UnorderedAccessView_mut() } = - d3d12::D3D12_INDIRECT_ARGUMENT_DESC_UnorderedAccessView { - RootParameterIndex: root_index, - }; - IndirectArgument(desc) - } -} - -#[repr(transparent)] -pub struct ResourceBarrier(d3d12::D3D12_RESOURCE_BARRIER); - -impl ResourceBarrier { - pub fn transition( - resource: Resource, - subresource: Subresource, - state_before: d3d12::D3D12_RESOURCE_STATES, - state_after: d3d12::D3D12_RESOURCE_STATES, - flags: d3d12::D3D12_RESOURCE_BARRIER_FLAGS, - ) -> Self { - let mut barrier = d3d12::D3D12_RESOURCE_BARRIER { - Type: d3d12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, - Flags: flags, - ..unsafe { mem::zeroed() } - }; - unsafe { - *barrier.u.Transition_mut() = d3d12::D3D12_RESOURCE_TRANSITION_BARRIER { - pResource: resource.as_mut_ptr(), - Subresource: subresource, - StateBefore: state_before, - StateAfter: state_after, - }; - } - ResourceBarrier(barrier) - } -} - -pub type CommandSignature = ComPtr; -pub type CommandList = ComPtr; -pub type GraphicsCommandList = ComPtr; - -impl GraphicsCommandList { - pub fn as_list(&self) -> CommandList { - unsafe { CommandList::from_raw(self.as_mut_ptr() as *mut _) } - } - - pub fn close(&self) -> HRESULT { - unsafe { self.Close() } - } - - pub fn reset(&self, allocator: &CommandAllocator, initial_pso: PipelineState) -> HRESULT { - unsafe { self.Reset(allocator.as_mut_ptr(), initial_pso.as_mut_ptr()) } - } - - pub fn discard_resource(&self, resource: Resource, region: DiscardRegion) { - debug_assert!(region.subregions.start < region.subregions.end); - unsafe { - self.DiscardResource( - resource.as_mut_ptr(), - &d3d12::D3D12_DISCARD_REGION { - NumRects: region.rects.len() as _, - pRects: region.rects.as_ptr(), - FirstSubresource: region.subregions.start, - NumSubresources: region.subregions.end - region.subregions.start - 1, - }, - ); - } - } - - pub fn clear_depth_stencil_view( - &self, - dsv: CpuDescriptor, - flags: ClearFlags, - depth: f32, - stencil: u8, - rects: &[Rect], - ) { - let num_rects = rects.len() as _; - let rects = if num_rects > 0 { - rects.as_ptr() - } else { - ptr::null() - }; - unsafe { - self.ClearDepthStencilView(dsv, flags.bits(), depth, stencil, num_rects, rects); - } - } - - pub fn clear_render_target_view(&self, rtv: CpuDescriptor, color: [f32; 4], rects: &[Rect]) { - let num_rects = rects.len() as _; - let rects = if num_rects > 0 { - rects.as_ptr() - } else { - ptr::null() - }; - unsafe { - self.ClearRenderTargetView(rtv, &color, num_rects, rects); - } - } - - pub fn dispatch(&self, count: WorkGroupCount) { - unsafe { - self.Dispatch(count[0], count[1], count[2]); - } - } - - pub fn draw( - &self, - num_vertices: VertexCount, - num_instances: InstanceCount, - first_vertex: VertexCount, - first_instance: InstanceCount, - ) { - unsafe { - self.DrawInstanced(num_vertices, num_instances, first_vertex, first_instance); - } - } - - pub fn draw_indexed( - &self, - num_indices: IndexCount, - num_instances: InstanceCount, - first_index: IndexCount, - base_vertex: VertexOffset, - first_instance: InstanceCount, - ) { - unsafe { - self.DrawIndexedInstanced( - num_indices, - num_instances, - first_index, - base_vertex, - first_instance, - ); - } - } - - pub fn set_index_buffer(&self, gpu_address: GpuAddress, size: u32, format: Format) { - let ibv = d3d12::D3D12_INDEX_BUFFER_VIEW { - BufferLocation: gpu_address, - SizeInBytes: size, - Format: format, - }; - unsafe { - self.IASetIndexBuffer(&ibv); - } - } - - pub fn set_blend_factor(&self, factor: [f32; 4]) { - unsafe { - self.OMSetBlendFactor(&factor); - } - } - - pub fn set_stencil_reference(&self, reference: u32) { - unsafe { - self.OMSetStencilRef(reference); - } - } - - pub fn set_pipeline_state(&self, pso: &PipelineState) { - unsafe { - self.SetPipelineState(pso.as_mut_ptr()); - } - } - - pub fn execute_bundle(&self, bundle: GraphicsCommandList) { - unsafe { - self.ExecuteBundle(bundle.as_mut_ptr()); - } - } - - pub fn set_descriptor_heaps(&self, heaps: &[DescriptorHeap]) { - unsafe { - self.SetDescriptorHeaps( - heaps.len() as _, - heaps.as_ptr() as *mut &DescriptorHeap as *mut _, - ); - } - } - - pub fn set_compute_root_signature(&self, signature: &RootSignature) { - unsafe { - self.SetComputeRootSignature(signature.as_mut_ptr()); - } - } - - pub fn set_graphics_root_signature(&self, signature: &RootSignature) { - unsafe { - self.SetGraphicsRootSignature(signature.as_mut_ptr()); - } - } - - pub fn set_compute_root_descriptor_table( - &self, - root_index: RootIndex, - base_descriptor: GpuDescriptor, - ) { - unsafe { - self.SetComputeRootDescriptorTable(root_index, base_descriptor); - } - } - - pub fn set_compute_root_constant_buffer_view( - &self, - root_index: RootIndex, - buffer_location: GpuAddress, - ) { - unsafe { - self.SetComputeRootConstantBufferView(root_index, buffer_location); - } - } - - pub fn set_compute_root_shader_resource_view( - &self, - root_index: RootIndex, - buffer_location: GpuAddress, - ) { - unsafe { - self.SetComputeRootShaderResourceView(root_index, buffer_location); - } - } - - pub fn set_compute_root_unordered_access_view( - &self, - root_index: RootIndex, - buffer_location: GpuAddress, - ) { - unsafe { - self.SetComputeRootUnorderedAccessView(root_index, buffer_location); - } - } - - pub fn set_compute_root_constant( - &self, - root_index: RootIndex, - value: u32, - dest_offset_words: u32, - ) { - unsafe { - self.SetComputeRoot32BitConstant(root_index, value, dest_offset_words); - } - } - - pub fn set_graphics_root_descriptor_table( - &self, - root_index: RootIndex, - base_descriptor: GpuDescriptor, - ) { - unsafe { - self.SetGraphicsRootDescriptorTable(root_index, base_descriptor); - } - } - - pub fn set_graphics_root_constant_buffer_view( - &self, - root_index: RootIndex, - buffer_location: GpuAddress, - ) { - unsafe { - self.SetGraphicsRootConstantBufferView(root_index, buffer_location); - } - } - - pub fn set_graphics_root_shader_resource_view( - &self, - root_index: RootIndex, - buffer_location: GpuAddress, - ) { - unsafe { - self.SetGraphicsRootShaderResourceView(root_index, buffer_location); - } - } - - pub fn set_graphics_root_unordered_access_view( - &self, - root_index: RootIndex, - buffer_location: GpuAddress, - ) { - unsafe { - self.SetGraphicsRootUnorderedAccessView(root_index, buffer_location); - } - } - - pub fn set_graphics_root_constant( - &self, - root_index: RootIndex, - value: u32, - dest_offset_words: u32, - ) { - unsafe { - self.SetGraphicsRoot32BitConstant(root_index, value, dest_offset_words); - } - } - - pub fn resource_barrier(&self, barriers: &[ResourceBarrier]) { - unsafe { - self.ResourceBarrier(barriers.len() as _, barriers.as_ptr() as _) // matches representation - } - } -} diff --git a/d3d12/src/debug.rs b/d3d12/src/debug.rs deleted file mode 100644 index f321d878d8..0000000000 --- a/d3d12/src/debug.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::com::ComPtr; -#[cfg(any(feature = "libloading", feature = "implicit-link"))] -use winapi::Interface as _; -use winapi::{ - shared::{minwindef::TRUE, winerror::S_OK}, - um::d3d12sdklayers, -}; - -pub type Debug = ComPtr; - -#[cfg(feature = "libloading")] -impl crate::D3D12Lib { - pub fn get_debug_interface(&self) -> Result, libloading::Error> { - type Fun = extern "system" fn( - winapi::shared::guiddef::REFIID, - *mut *mut winapi::ctypes::c_void, - ) -> crate::HRESULT; - - let mut debug = Debug::null(); - let hr = unsafe { - let func: libloading::Symbol = self.lib.get(b"D3D12GetDebugInterface")?; - func(&d3d12sdklayers::ID3D12Debug::uuidof(), debug.mut_void()) - }; - - Ok((debug, hr)) - } -} - -impl Debug { - #[cfg(feature = "implicit-link")] - pub fn get_interface() -> crate::D3DResult { - let mut debug = Debug::null(); - let hr = unsafe { - winapi::um::d3d12::D3D12GetDebugInterface( - &d3d12sdklayers::ID3D12Debug::uuidof(), - debug.mut_void(), - ) - }; - - (debug, hr) - } - - pub fn enable_layer(&self) { - unsafe { self.EnableDebugLayer() } - } - - pub fn enable_gpu_based_validation(&self) -> bool { - let (ptr, hr) = unsafe { self.cast::() }; - if hr == S_OK { - unsafe { ptr.SetEnableGPUBasedValidation(TRUE) }; - true - } else { - false - } - } -} diff --git a/d3d12/src/descriptor.rs b/d3d12/src/descriptor.rs deleted file mode 100644 index b2c3ab23b9..0000000000 --- a/d3d12/src/descriptor.rs +++ /dev/null @@ -1,362 +0,0 @@ -use crate::{com::ComPtr, Blob, D3DResult, Error, TextureAddressMode}; -use std::{fmt, mem, ops::Range}; -use winapi::{shared::dxgiformat, um::d3d12}; - -pub type CpuDescriptor = d3d12::D3D12_CPU_DESCRIPTOR_HANDLE; -pub type GpuDescriptor = d3d12::D3D12_GPU_DESCRIPTOR_HANDLE; - -#[derive(Clone, Copy, Debug)] -pub struct Binding { - pub space: u32, - pub register: u32, -} - -#[repr(u32)] -#[derive(Clone, Copy, Debug)] -pub enum DescriptorHeapType { - CbvSrvUav = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - Sampler = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, - Rtv = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_RTV, - Dsv = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_DSV, -} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct DescriptorHeapFlags: u32 { - const SHADER_VISIBLE = d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - } -} - -pub type DescriptorHeap = ComPtr; - -impl DescriptorHeap { - pub fn start_cpu_descriptor(&self) -> CpuDescriptor { - unsafe { self.GetCPUDescriptorHandleForHeapStart() } - } - - pub fn start_gpu_descriptor(&self) -> GpuDescriptor { - unsafe { self.GetGPUDescriptorHandleForHeapStart() } - } -} - -#[repr(u32)] -#[derive(Clone, Copy, Debug)] -pub enum ShaderVisibility { - All = d3d12::D3D12_SHADER_VISIBILITY_ALL, - VS = d3d12::D3D12_SHADER_VISIBILITY_VERTEX, - HS = d3d12::D3D12_SHADER_VISIBILITY_HULL, - DS = d3d12::D3D12_SHADER_VISIBILITY_DOMAIN, - GS = d3d12::D3D12_SHADER_VISIBILITY_GEOMETRY, - PS = d3d12::D3D12_SHADER_VISIBILITY_PIXEL, -} - -#[repr(u32)] -#[derive(Clone, Copy, Debug)] -pub enum DescriptorRangeType { - SRV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV, - UAV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV, - CBV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV, - Sampler = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, -} - -#[repr(transparent)] -pub struct DescriptorRange(d3d12::D3D12_DESCRIPTOR_RANGE); -impl DescriptorRange { - pub fn new(ty: DescriptorRangeType, count: u32, base_binding: Binding, offset: u32) -> Self { - DescriptorRange(d3d12::D3D12_DESCRIPTOR_RANGE { - RangeType: ty as _, - NumDescriptors: count, - BaseShaderRegister: base_binding.register, - RegisterSpace: base_binding.space, - OffsetInDescriptorsFromTableStart: offset, - }) - } -} - -impl fmt::Debug for DescriptorRange { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter - .debug_struct("DescriptorRange") - .field("range_type", &self.0.RangeType) - .field("num", &self.0.NumDescriptors) - .field("register_space", &self.0.RegisterSpace) - .field("base_register", &self.0.BaseShaderRegister) - .field("table_offset", &self.0.OffsetInDescriptorsFromTableStart) - .finish() - } -} - -#[repr(transparent)] -pub struct RootParameter(d3d12::D3D12_ROOT_PARAMETER); -impl RootParameter { - // TODO: DescriptorRange must outlive Self - pub fn descriptor_table(visibility: ShaderVisibility, ranges: &[DescriptorRange]) -> Self { - let mut param = d3d12::D3D12_ROOT_PARAMETER { - ParameterType: d3d12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, - ShaderVisibility: visibility as _, - ..unsafe { mem::zeroed() } - }; - - *unsafe { param.u.DescriptorTable_mut() } = d3d12::D3D12_ROOT_DESCRIPTOR_TABLE { - NumDescriptorRanges: ranges.len() as _, - pDescriptorRanges: ranges.as_ptr() as *const _, - }; - - RootParameter(param) - } - - pub fn constants(visibility: ShaderVisibility, binding: Binding, num: u32) -> Self { - let mut param = d3d12::D3D12_ROOT_PARAMETER { - ParameterType: d3d12::D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, - ShaderVisibility: visibility as _, - ..unsafe { mem::zeroed() } - }; - - *unsafe { param.u.Constants_mut() } = d3d12::D3D12_ROOT_CONSTANTS { - ShaderRegister: binding.register, - RegisterSpace: binding.space, - Num32BitValues: num, - }; - - RootParameter(param) - } - - //TODO: should this be unsafe? - pub fn descriptor( - ty: d3d12::D3D12_ROOT_PARAMETER_TYPE, - visibility: ShaderVisibility, - binding: Binding, - ) -> Self { - let mut param = d3d12::D3D12_ROOT_PARAMETER { - ParameterType: ty, - ShaderVisibility: visibility as _, - ..unsafe { mem::zeroed() } - }; - - *unsafe { param.u.Descriptor_mut() } = d3d12::D3D12_ROOT_DESCRIPTOR { - ShaderRegister: binding.register, - RegisterSpace: binding.space, - }; - - RootParameter(param) - } - - pub fn cbv_descriptor(visibility: ShaderVisibility, binding: Binding) -> Self { - Self::descriptor(d3d12::D3D12_ROOT_PARAMETER_TYPE_CBV, visibility, binding) - } - - pub fn srv_descriptor(visibility: ShaderVisibility, binding: Binding) -> Self { - Self::descriptor(d3d12::D3D12_ROOT_PARAMETER_TYPE_SRV, visibility, binding) - } - - pub fn uav_descriptor(visibility: ShaderVisibility, binding: Binding) -> Self { - Self::descriptor(d3d12::D3D12_ROOT_PARAMETER_TYPE_UAV, visibility, binding) - } -} - -impl fmt::Debug for RootParameter { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - #[derive(Debug)] - #[allow(dead_code)] // False-positive - enum Inner<'a> { - Table(&'a [DescriptorRange]), - Constants { binding: Binding, num: u32 }, - SingleCbv(Binding), - SingleSrv(Binding), - SingleUav(Binding), - } - let kind = match self.0.ParameterType { - d3d12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE => unsafe { - let raw = self.0.u.DescriptorTable(); - Inner::Table(std::slice::from_raw_parts( - raw.pDescriptorRanges as *const _, - raw.NumDescriptorRanges as usize, - )) - }, - d3d12::D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS => unsafe { - let raw = self.0.u.Constants(); - Inner::Constants { - binding: Binding { - space: raw.RegisterSpace, - register: raw.ShaderRegister, - }, - num: raw.Num32BitValues, - } - }, - _ => unsafe { - let raw = self.0.u.Descriptor(); - let binding = Binding { - space: raw.RegisterSpace, - register: raw.ShaderRegister, - }; - match self.0.ParameterType { - d3d12::D3D12_ROOT_PARAMETER_TYPE_CBV => Inner::SingleCbv(binding), - d3d12::D3D12_ROOT_PARAMETER_TYPE_SRV => Inner::SingleSrv(binding), - d3d12::D3D12_ROOT_PARAMETER_TYPE_UAV => Inner::SingleUav(binding), - other => panic!("Unexpected type {:?}", other), - } - }, - }; - - formatter - .debug_struct("RootParameter") - .field("visibility", &self.0.ShaderVisibility) - .field("kind", &kind) - .finish() - } -} - -#[repr(u32)] -#[derive(Copy, Clone, Debug)] -pub enum StaticBorderColor { - TransparentBlack = d3d12::D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK, - OpaqueBlack = d3d12::D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK, - OpaqueWhite = d3d12::D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE, -} - -#[repr(transparent)] -pub struct StaticSampler(d3d12::D3D12_STATIC_SAMPLER_DESC); -impl StaticSampler { - pub fn new( - visibility: ShaderVisibility, - binding: Binding, - filter: d3d12::D3D12_FILTER, - address_mode: TextureAddressMode, - mip_lod_bias: f32, - max_anisotropy: u32, - comparison_op: d3d12::D3D12_COMPARISON_FUNC, - border_color: StaticBorderColor, - lod: Range, - ) -> Self { - StaticSampler(d3d12::D3D12_STATIC_SAMPLER_DESC { - Filter: filter, - AddressU: address_mode[0], - AddressV: address_mode[1], - AddressW: address_mode[2], - MipLODBias: mip_lod_bias, - MaxAnisotropy: max_anisotropy, - ComparisonFunc: comparison_op, - BorderColor: border_color as _, - MinLOD: lod.start, - MaxLOD: lod.end, - ShaderRegister: binding.register, - RegisterSpace: binding.space, - ShaderVisibility: visibility as _, - }) - } -} - -#[repr(u32)] -#[derive(Copy, Clone, Debug)] -pub enum RootSignatureVersion { - V1_0 = d3d12::D3D_ROOT_SIGNATURE_VERSION_1_0, - V1_1 = d3d12::D3D_ROOT_SIGNATURE_VERSION_1_1, -} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct RootSignatureFlags: u32 { - const ALLOW_IA_INPUT_LAYOUT = d3d12::D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; - const DENY_VS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS; - const DENY_HS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS; - const DENY_DS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS; - const DENY_GS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; - const DENY_PS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; - } -} - -pub type RootSignature = ComPtr; -pub type BlobResult = D3DResult<(Blob, Error)>; - -#[cfg(feature = "libloading")] -impl crate::D3D12Lib { - pub fn serialize_root_signature( - &self, - version: RootSignatureVersion, - parameters: &[RootParameter], - static_samplers: &[StaticSampler], - flags: RootSignatureFlags, - ) -> Result { - use winapi::um::d3dcommon::ID3DBlob; - type Fun = extern "system" fn( - *const d3d12::D3D12_ROOT_SIGNATURE_DESC, - d3d12::D3D_ROOT_SIGNATURE_VERSION, - *mut *mut ID3DBlob, - *mut *mut ID3DBlob, - ) -> crate::HRESULT; - - let desc = d3d12::D3D12_ROOT_SIGNATURE_DESC { - NumParameters: parameters.len() as _, - pParameters: parameters.as_ptr() as *const _, - NumStaticSamplers: static_samplers.len() as _, - pStaticSamplers: static_samplers.as_ptr() as _, - Flags: flags.bits(), - }; - - let mut blob = Blob::null(); - let mut error = Error::null(); - let hr = unsafe { - let func: libloading::Symbol = self.lib.get(b"D3D12SerializeRootSignature")?; - func( - &desc, - version as _, - blob.mut_void() as *mut *mut _, - error.mut_void() as *mut *mut _, - ) - }; - - Ok(((blob, error), hr)) - } -} - -impl RootSignature { - #[cfg(feature = "implicit-link")] - pub fn serialize( - version: RootSignatureVersion, - parameters: &[RootParameter], - static_samplers: &[StaticSampler], - flags: RootSignatureFlags, - ) -> BlobResult { - let mut blob = Blob::null(); - let mut error = Error::null(); - - let desc = d3d12::D3D12_ROOT_SIGNATURE_DESC { - NumParameters: parameters.len() as _, - pParameters: parameters.as_ptr() as *const _, - NumStaticSamplers: static_samplers.len() as _, - pStaticSamplers: static_samplers.as_ptr() as _, - Flags: flags.bits(), - }; - - let hr = unsafe { - d3d12::D3D12SerializeRootSignature( - &desc, - version as _, - blob.mut_void() as *mut *mut _, - error.mut_void() as *mut *mut _, - ) - }; - - ((blob, error), hr) - } -} - -#[repr(transparent)] -pub struct RenderTargetViewDesc(pub(crate) d3d12::D3D12_RENDER_TARGET_VIEW_DESC); - -impl RenderTargetViewDesc { - pub fn texture_2d(format: dxgiformat::DXGI_FORMAT, mip_slice: u32, plane_slice: u32) -> Self { - let mut desc = d3d12::D3D12_RENDER_TARGET_VIEW_DESC { - Format: format, - ViewDimension: d3d12::D3D12_RTV_DIMENSION_TEXTURE2D, - ..unsafe { mem::zeroed() } - }; - - *unsafe { desc.u.Texture2D_mut() } = d3d12::D3D12_TEX2D_RTV { - MipSlice: mip_slice, - PlaneSlice: plane_slice, - }; - - RenderTargetViewDesc(desc) - } -} diff --git a/d3d12/src/device.rs b/d3d12/src/device.rs deleted file mode 100644 index 475fa22b50..0000000000 --- a/d3d12/src/device.rs +++ /dev/null @@ -1,344 +0,0 @@ -//! Device - -use crate::{ - com::ComPtr, - command_list::{CmdListType, CommandSignature, IndirectArgument}, - descriptor::{CpuDescriptor, DescriptorHeapFlags, DescriptorHeapType, RenderTargetViewDesc}, - heap::{Heap, HeapFlags, HeapProperties}, - pso, query, queue, Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, - Fence, GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, - Shader, TextureAddressMode, -}; -use std::ops::Range; -use winapi::{um::d3d12, Interface}; - -pub type Device = ComPtr; - -#[cfg(feature = "libloading")] -impl crate::D3D12Lib { - pub fn create_device( - &self, - adapter: &ComPtr, - feature_level: crate::FeatureLevel, - ) -> Result, libloading::Error> { - type Fun = extern "system" fn( - *mut winapi::um::unknwnbase::IUnknown, - winapi::um::d3dcommon::D3D_FEATURE_LEVEL, - winapi::shared::guiddef::REFGUID, - *mut *mut winapi::ctypes::c_void, - ) -> crate::HRESULT; - - let mut device = Device::null(); - let hr = unsafe { - let func: libloading::Symbol = self.lib.get(b"D3D12CreateDevice")?; - func( - adapter.as_unknown() as *const _ as *mut _, - feature_level as _, - &d3d12::ID3D12Device::uuidof(), - device.mut_void(), - ) - }; - - Ok((device, hr)) - } -} - -impl Device { - #[cfg(feature = "implicit-link")] - pub fn create( - adapter: ComPtr, - feature_level: crate::FeatureLevel, - ) -> D3DResult { - let mut device = Device::null(); - let hr = unsafe { - d3d12::D3D12CreateDevice( - adapter.as_unknown() as *const _ as *mut _, - feature_level as _, - &d3d12::ID3D12Device::uuidof(), - device.mut_void(), - ) - }; - - (device, hr) - } - - pub fn create_heap( - &self, - size_in_bytes: u64, - properties: HeapProperties, - alignment: u64, - flags: HeapFlags, - ) -> D3DResult { - let mut heap = Heap::null(); - - let desc = d3d12::D3D12_HEAP_DESC { - SizeInBytes: size_in_bytes, - Properties: properties.0, - Alignment: alignment, - Flags: flags.bits(), - }; - - let hr = unsafe { self.CreateHeap(&desc, &d3d12::ID3D12Heap::uuidof(), heap.mut_void()) }; - - (heap, hr) - } - - pub fn create_command_allocator(&self, list_type: CmdListType) -> D3DResult { - let mut allocator = CommandAllocator::null(); - let hr = unsafe { - self.CreateCommandAllocator( - list_type as _, - &d3d12::ID3D12CommandAllocator::uuidof(), - allocator.mut_void(), - ) - }; - - (allocator, hr) - } - - pub fn create_command_queue( - &self, - list_type: CmdListType, - priority: queue::Priority, - flags: queue::CommandQueueFlags, - node_mask: NodeMask, - ) -> D3DResult { - let desc = d3d12::D3D12_COMMAND_QUEUE_DESC { - Type: list_type as _, - Priority: priority as _, - Flags: flags.bits(), - NodeMask: node_mask, - }; - - let mut queue = CommandQueue::null(); - let hr = unsafe { - self.CreateCommandQueue( - &desc, - &d3d12::ID3D12CommandQueue::uuidof(), - queue.mut_void(), - ) - }; - - (queue, hr) - } - - pub fn create_descriptor_heap( - &self, - num_descriptors: u32, - heap_type: DescriptorHeapType, - flags: DescriptorHeapFlags, - node_mask: NodeMask, - ) -> D3DResult { - let desc = d3d12::D3D12_DESCRIPTOR_HEAP_DESC { - Type: heap_type as _, - NumDescriptors: num_descriptors, - Flags: flags.bits(), - NodeMask: node_mask, - }; - - let mut heap = DescriptorHeap::null(); - let hr = unsafe { - self.CreateDescriptorHeap( - &desc, - &d3d12::ID3D12DescriptorHeap::uuidof(), - heap.mut_void(), - ) - }; - - (heap, hr) - } - - pub fn get_descriptor_increment_size(&self, heap_type: DescriptorHeapType) -> u32 { - unsafe { self.GetDescriptorHandleIncrementSize(heap_type as _) } - } - - pub fn create_graphics_command_list( - &self, - list_type: CmdListType, - allocator: &CommandAllocator, - initial: PipelineState, - node_mask: NodeMask, - ) -> D3DResult { - let mut command_list = GraphicsCommandList::null(); - let hr = unsafe { - self.CreateCommandList( - node_mask, - list_type as _, - allocator.as_mut_ptr(), - initial.as_mut_ptr(), - &d3d12::ID3D12GraphicsCommandList::uuidof(), - command_list.mut_void(), - ) - }; - - (command_list, hr) - } - - pub fn create_query_heap( - &self, - heap_ty: query::QueryHeapType, - count: u32, - node_mask: NodeMask, - ) -> D3DResult { - let desc = d3d12::D3D12_QUERY_HEAP_DESC { - Type: heap_ty as _, - Count: count, - NodeMask: node_mask, - }; - - let mut query_heap = QueryHeap::null(); - let hr = unsafe { - self.CreateQueryHeap( - &desc, - &d3d12::ID3D12QueryHeap::uuidof(), - query_heap.mut_void(), - ) - }; - - (query_heap, hr) - } - - pub fn create_graphics_pipeline_state( - &self, - _root_signature: RootSignature, - _vs: Shader, - _ps: Shader, - _gs: Shader, - _hs: Shader, - _ds: Shader, - _node_mask: NodeMask, - _cached_pso: CachedPSO, - _flags: pso::PipelineStateFlags, - ) -> D3DResult { - unimplemented!() - } - - pub fn create_compute_pipeline_state( - &self, - root_signature: &RootSignature, - cs: Shader, - node_mask: NodeMask, - cached_pso: CachedPSO, - flags: pso::PipelineStateFlags, - ) -> D3DResult { - let mut pipeline = PipelineState::null(); - let desc = d3d12::D3D12_COMPUTE_PIPELINE_STATE_DESC { - pRootSignature: root_signature.as_mut_ptr(), - CS: *cs, - NodeMask: node_mask, - CachedPSO: *cached_pso, - Flags: flags.bits(), - }; - - let hr = unsafe { - self.CreateComputePipelineState( - &desc, - &d3d12::ID3D12PipelineState::uuidof(), - pipeline.mut_void(), - ) - }; - - (pipeline, hr) - } - - pub fn create_sampler( - &self, - sampler: CpuDescriptor, - filter: d3d12::D3D12_FILTER, - address_mode: TextureAddressMode, - mip_lod_bias: f32, - max_anisotropy: u32, - comparison_op: d3d12::D3D12_COMPARISON_FUNC, - border_color: [f32; 4], - lod: Range, - ) { - let desc = d3d12::D3D12_SAMPLER_DESC { - Filter: filter, - AddressU: address_mode[0], - AddressV: address_mode[1], - AddressW: address_mode[2], - MipLODBias: mip_lod_bias, - MaxAnisotropy: max_anisotropy, - ComparisonFunc: comparison_op, - BorderColor: border_color, - MinLOD: lod.start, - MaxLOD: lod.end, - }; - - unsafe { - self.CreateSampler(&desc, sampler); - } - } - - pub fn create_root_signature( - &self, - blob: Blob, - node_mask: NodeMask, - ) -> D3DResult { - let mut signature = RootSignature::null(); - let hr = unsafe { - self.CreateRootSignature( - node_mask, - blob.GetBufferPointer(), - blob.GetBufferSize(), - &d3d12::ID3D12RootSignature::uuidof(), - signature.mut_void(), - ) - }; - - (signature, hr) - } - - pub fn create_command_signature( - &self, - root_signature: RootSignature, - arguments: &[IndirectArgument], - stride: u32, - node_mask: NodeMask, - ) -> D3DResult { - let mut signature = CommandSignature::null(); - let desc = d3d12::D3D12_COMMAND_SIGNATURE_DESC { - ByteStride: stride, - NumArgumentDescs: arguments.len() as _, - pArgumentDescs: arguments.as_ptr() as *const _, - NodeMask: node_mask, - }; - - let hr = unsafe { - self.CreateCommandSignature( - &desc, - root_signature.as_mut_ptr(), - &d3d12::ID3D12CommandSignature::uuidof(), - signature.mut_void(), - ) - }; - - (signature, hr) - } - - pub fn create_render_target_view( - &self, - resource: Resource, - desc: &RenderTargetViewDesc, - descriptor: CpuDescriptor, - ) { - unsafe { - self.CreateRenderTargetView(resource.as_mut_ptr(), &desc.0 as *const _, descriptor); - } - } - - // TODO: interface not complete - pub fn create_fence(&self, initial: u64) -> D3DResult { - let mut fence = Fence::null(); - let hr = unsafe { - self.CreateFence( - initial, - d3d12::D3D12_FENCE_FLAG_NONE, - &d3d12::ID3D12Fence::uuidof(), - fence.mut_void(), - ) - }; - - (fence, hr) - } -} diff --git a/d3d12/src/dxgi.rs b/d3d12/src/dxgi.rs deleted file mode 100644 index 0cbb5bb63b..0000000000 --- a/d3d12/src/dxgi.rs +++ /dev/null @@ -1,377 +0,0 @@ -use crate::{com::ComPtr, D3DResult, Resource, SampleDesc, HRESULT}; -use std::ptr; -use winapi::{ - shared::{ - dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgi1_5, dxgi1_6, dxgiformat, dxgitype, minwindef::TRUE, - windef::HWND, - }, - um::{d3d12, dxgidebug, unknwnbase::IUnknown, winnt::HANDLE}, - Interface, -}; - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct FactoryCreationFlags: u32 { - const DEBUG = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG; - } -} - -#[repr(u32)] -#[derive(Debug, Copy, Clone)] -pub enum Scaling { - Stretch = dxgi1_2::DXGI_SCALING_STRETCH, - Identity = dxgi1_2::DXGI_SCALING_NONE, - Aspect = dxgi1_2::DXGI_SCALING_ASPECT_RATIO_STRETCH, -} - -#[repr(u32)] -#[derive(Debug, Copy, Clone)] -pub enum SwapEffect { - Discard = dxgi::DXGI_SWAP_EFFECT_DISCARD, - Sequential = dxgi::DXGI_SWAP_EFFECT_SEQUENTIAL, - FlipDiscard = dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD, - FlipSequential = dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, -} - -#[repr(u32)] -#[derive(Debug, Copy, Clone)] -pub enum AlphaMode { - Unspecified = dxgi1_2::DXGI_ALPHA_MODE_UNSPECIFIED, - Premultiplied = dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED, - Straight = dxgi1_2::DXGI_ALPHA_MODE_STRAIGHT, - Ignore = dxgi1_2::DXGI_ALPHA_MODE_IGNORE, - ForceDword = dxgi1_2::DXGI_ALPHA_MODE_FORCE_DWORD, -} - -pub type InfoQueue = ComPtr; - -pub type Adapter1 = ComPtr; -pub type Adapter2 = ComPtr; -pub type Adapter3 = ComPtr; -pub type Adapter4 = ComPtr; -crate::weak_com_inheritance_chain! { - #[derive(Debug, Clone, PartialEq, Hash)] - pub enum DxgiAdapter { - Adapter1(dxgi::IDXGIAdapter1), from_adapter1, as_adapter1, adapter1; - Adapter2(dxgi1_2::IDXGIAdapter2), from_adapter2, as_adapter2, unwrap_adapter2; - Adapter3(dxgi1_4::IDXGIAdapter3), from_adapter3, as_adapter3, unwrap_adapter3; - Adapter4(dxgi1_6::IDXGIAdapter4), from_adapter4, as_adapter4, unwrap_adapter4; - } -} - -pub type Factory1 = ComPtr; -pub type Factory2 = ComPtr; -pub type Factory3 = ComPtr; -pub type Factory4 = ComPtr; -pub type Factory5 = ComPtr; -pub type Factory6 = ComPtr; -crate::weak_com_inheritance_chain! { - #[derive(Debug, Clone, PartialEq, Hash)] - pub enum DxgiFactory { - Factory1(dxgi::IDXGIFactory1), from_factory1, as_factory1, factory1; - Factory2(dxgi1_2::IDXGIFactory2), from_factory2, as_factory2, unwrap_factory2; - Factory3(dxgi1_3::IDXGIFactory3), from_factory3, as_factory3, unwrap_factory3; - Factory4(dxgi1_4::IDXGIFactory4), from_factory4, as_factory4, unwrap_factory4; - Factory5(dxgi1_5::IDXGIFactory5), from_factory5, as_factory5, unwrap_factory5; - Factory6(dxgi1_6::IDXGIFactory6), from_factory6, as_factory6, unwrap_factory6; - } -} - -pub type FactoryMedia = ComPtr; - -pub type SwapChain = ComPtr; -pub type SwapChain1 = ComPtr; -pub type SwapChain2 = ComPtr; -pub type SwapChain3 = ComPtr; -crate::weak_com_inheritance_chain! { - #[derive(Debug, Clone, PartialEq, Hash)] - pub enum DxgiSwapchain { - SwapChain(dxgi::IDXGISwapChain), from_swap_chain, as_swap_chain, swap_chain; - SwapChain1(dxgi1_2::IDXGISwapChain1), from_swap_chain1, as_swap_chain1, unwrap_swap_chain1; - SwapChain2(dxgi1_3::IDXGISwapChain2), from_swap_chain2, as_swap_chain2, unwrap_swap_chain2; - SwapChain3(dxgi1_4::IDXGISwapChain3), from_swap_chain3, as_swap_chain3, unwrap_swap_chain3; - } -} - -#[cfg(feature = "libloading")] -#[derive(Debug)] -pub struct DxgiLib { - lib: libloading::Library, -} - -#[cfg(feature = "libloading")] -impl DxgiLib { - pub fn new() -> Result { - unsafe { libloading::Library::new("dxgi.dll").map(|lib| DxgiLib { lib }) } - } - - pub fn create_factory2( - &self, - flags: FactoryCreationFlags, - ) -> Result, libloading::Error> { - type Fun = extern "system" fn( - winapi::shared::minwindef::UINT, - winapi::shared::guiddef::REFIID, - *mut *mut winapi::ctypes::c_void, - ) -> HRESULT; - - let mut factory = Factory4::null(); - let hr = unsafe { - let func: libloading::Symbol = self.lib.get(b"CreateDXGIFactory2")?; - func( - flags.bits(), - &dxgi1_4::IDXGIFactory4::uuidof(), - factory.mut_void(), - ) - }; - - Ok((factory, hr)) - } - - pub fn create_factory1(&self) -> Result, libloading::Error> { - type Fun = extern "system" fn( - winapi::shared::guiddef::REFIID, - *mut *mut winapi::ctypes::c_void, - ) -> HRESULT; - - let mut factory = Factory1::null(); - let hr = unsafe { - let func: libloading::Symbol = self.lib.get(b"CreateDXGIFactory1")?; - func(&dxgi::IDXGIFactory1::uuidof(), factory.mut_void()) - }; - - Ok((factory, hr)) - } - - pub fn create_factory_media(&self) -> Result, libloading::Error> { - type Fun = extern "system" fn( - winapi::shared::guiddef::REFIID, - *mut *mut winapi::ctypes::c_void, - ) -> HRESULT; - - let mut factory = FactoryMedia::null(); - let hr = unsafe { - // https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nn-dxgi1_3-idxgifactorymedia - let func: libloading::Symbol = self.lib.get(b"CreateDXGIFactory1")?; - func(&dxgi1_3::IDXGIFactoryMedia::uuidof(), factory.mut_void()) - }; - - Ok((factory, hr)) - } - - pub fn get_debug_interface1(&self) -> Result, libloading::Error> { - type Fun = extern "system" fn( - winapi::shared::minwindef::UINT, - winapi::shared::guiddef::REFIID, - *mut *mut winapi::ctypes::c_void, - ) -> HRESULT; - - let mut queue = InfoQueue::null(); - let hr = unsafe { - let func: libloading::Symbol = self.lib.get(b"DXGIGetDebugInterface1")?; - func(0, &dxgidebug::IDXGIInfoQueue::uuidof(), queue.mut_void()) - }; - Ok((queue, hr)) - } -} - -// TODO: strong types -pub struct SwapchainDesc { - pub width: u32, - pub height: u32, - pub format: dxgiformat::DXGI_FORMAT, - pub stereo: bool, - pub sample: SampleDesc, - pub buffer_usage: dxgitype::DXGI_USAGE, - pub buffer_count: u32, - pub scaling: Scaling, - pub swap_effect: SwapEffect, - pub alpha_mode: AlphaMode, - pub flags: u32, -} -impl SwapchainDesc { - pub fn to_desc1(&self) -> dxgi1_2::DXGI_SWAP_CHAIN_DESC1 { - dxgi1_2::DXGI_SWAP_CHAIN_DESC1 { - AlphaMode: self.alpha_mode as _, - BufferCount: self.buffer_count, - Width: self.width, - Height: self.height, - Format: self.format, - Flags: self.flags, - BufferUsage: self.buffer_usage, - SampleDesc: dxgitype::DXGI_SAMPLE_DESC { - Count: self.sample.count, - Quality: self.sample.quality, - }, - Scaling: self.scaling as _, - Stereo: self.stereo as _, - SwapEffect: self.swap_effect as _, - } - } -} - -impl Factory1 { - pub fn create_swapchain( - &self, - queue: *mut IUnknown, - hwnd: HWND, - desc: &SwapchainDesc, - ) -> D3DResult { - let mut desc = dxgi::DXGI_SWAP_CHAIN_DESC { - BufferDesc: dxgitype::DXGI_MODE_DESC { - Width: desc.width, - Height: desc.width, - RefreshRate: dxgitype::DXGI_RATIONAL { - Numerator: 1, - Denominator: 60, - }, - Format: desc.format, - ScanlineOrdering: dxgitype::DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, - Scaling: dxgitype::DXGI_MODE_SCALING_UNSPECIFIED, - }, - SampleDesc: dxgitype::DXGI_SAMPLE_DESC { - Count: desc.sample.count, - Quality: desc.sample.quality, - }, - BufferUsage: desc.buffer_usage, - BufferCount: desc.buffer_count, - OutputWindow: hwnd, - Windowed: TRUE, - SwapEffect: desc.swap_effect as _, - Flags: desc.flags, - }; - - let mut swapchain = SwapChain::null(); - let hr = - unsafe { self.CreateSwapChain(queue, &mut desc, swapchain.mut_void() as *mut *mut _) }; - - (swapchain, hr) - } -} - -impl Factory2 { - // TODO: interface not complete - pub fn create_swapchain_for_hwnd( - &self, - queue: *mut IUnknown, - hwnd: HWND, - desc: &SwapchainDesc, - ) -> D3DResult { - let mut swap_chain = SwapChain1::null(); - let hr = unsafe { - self.CreateSwapChainForHwnd( - queue, - hwnd, - &desc.to_desc1(), - ptr::null(), - ptr::null_mut(), - swap_chain.mut_void() as *mut *mut _, - ) - }; - - (swap_chain, hr) - } - - pub fn create_swapchain_for_composition( - &self, - queue: *mut IUnknown, - desc: &SwapchainDesc, - ) -> D3DResult { - let mut swap_chain = SwapChain1::null(); - let hr = unsafe { - self.CreateSwapChainForComposition( - queue, - &desc.to_desc1(), - ptr::null_mut(), - swap_chain.mut_void() as *mut *mut _, - ) - }; - - (swap_chain, hr) - } -} - -impl Factory4 { - #[cfg(feature = "implicit-link")] - pub fn create(flags: FactoryCreationFlags) -> D3DResult { - let mut factory = Factory4::null(); - let hr = unsafe { - dxgi1_3::CreateDXGIFactory2( - flags.bits(), - &dxgi1_4::IDXGIFactory4::uuidof(), - factory.mut_void(), - ) - }; - - (factory, hr) - } - - pub fn enumerate_adapters(&self, id: u32) -> D3DResult { - let mut adapter = Adapter1::null(); - let hr = unsafe { self.EnumAdapters1(id, adapter.mut_void() as *mut *mut _) }; - - (adapter, hr) - } -} - -impl FactoryMedia { - pub fn create_swapchain_for_composition_surface_handle( - &self, - queue: *mut IUnknown, - surface_handle: HANDLE, - desc: &SwapchainDesc, - ) -> D3DResult { - let mut swap_chain = SwapChain1::null(); - let hr = unsafe { - self.CreateSwapChainForCompositionSurfaceHandle( - queue, - surface_handle, - &desc.to_desc1(), - ptr::null_mut(), - swap_chain.mut_void() as *mut *mut _, - ) - }; - - (swap_chain, hr) - } -} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct SwapChainPresentFlags: u32 { - const DXGI_PRESENT_DO_NOT_SEQUENCE = dxgi::DXGI_PRESENT_DO_NOT_SEQUENCE; - const DXGI_PRESENT_TEST = dxgi::DXGI_PRESENT_TEST; - const DXGI_PRESENT_RESTART = dxgi::DXGI_PRESENT_RESTART; - const DXGI_PRESENT_DO_NOT_WAIT = dxgi::DXGI_PRESENT_DO_NOT_WAIT; - const DXGI_PRESENT_RESTRICT_TO_OUTPUT = dxgi::DXGI_PRESENT_RESTRICT_TO_OUTPUT; - const DXGI_PRESENT_STEREO_PREFER_RIGHT = dxgi::DXGI_PRESENT_STEREO_PREFER_RIGHT; - const DXGI_PRESENT_STEREO_TEMPORARY_MONO = dxgi::DXGI_PRESENT_STEREO_TEMPORARY_MONO; - const DXGI_PRESENT_USE_DURATION = dxgi::DXGI_PRESENT_USE_DURATION; - const DXGI_PRESENT_ALLOW_TEARING = dxgi::DXGI_PRESENT_ALLOW_TEARING; - } -} - -impl SwapChain { - pub fn get_buffer(&self, id: u32) -> D3DResult { - let mut resource = Resource::null(); - let hr = - unsafe { self.GetBuffer(id, &d3d12::ID3D12Resource::uuidof(), resource.mut_void()) }; - - (resource, hr) - } - - //TODO: replace by present_flags - pub fn present(&self, interval: u32, flags: u32) -> HRESULT { - unsafe { self.Present(interval, flags) } - } - - pub fn present_flags(&self, interval: u32, flags: SwapChainPresentFlags) -> HRESULT { - unsafe { self.Present(interval, flags.bits()) } - } -} - -impl SwapChain3 { - pub fn get_current_back_buffer_index(&self) -> u32 { - unsafe { self.GetCurrentBackBufferIndex() } - } -} diff --git a/d3d12/src/heap.rs b/d3d12/src/heap.rs deleted file mode 100644 index 074de56d77..0000000000 --- a/d3d12/src/heap.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::com::ComPtr; -use winapi::um::d3d12; - -pub type Heap = ComPtr; - -#[repr(u32)] -#[derive(Clone, Copy)] -pub enum HeapType { - Default = d3d12::D3D12_HEAP_TYPE_DEFAULT, - Upload = d3d12::D3D12_HEAP_TYPE_UPLOAD, - Readback = d3d12::D3D12_HEAP_TYPE_READBACK, - Custom = d3d12::D3D12_HEAP_TYPE_CUSTOM, -} - -#[repr(u32)] -#[derive(Clone, Copy)] -pub enum CpuPageProperty { - Unknown = d3d12::D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - NotAvailable = d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, - WriteCombine = d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE, - WriteBack = d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK, -} - -#[repr(u32)] -#[derive(Clone, Copy)] -pub enum MemoryPool { - Unknown = d3d12::D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - L0 = d3d12::D3D12_MEMORY_POOL_L0, - L1 = d3d12::D3D12_MEMORY_POOL_L1, -} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct HeapFlags: u32 { - const NONE = d3d12::D3D12_HEAP_FLAG_NONE; - const SHARED = d3d12::D3D12_HEAP_FLAG_SHARED; - const DENY_BUFFERS = d3d12::D3D12_HEAP_FLAG_DENY_BUFFERS; - const ALLOW_DISPLAY = d3d12::D3D12_HEAP_FLAG_ALLOW_DISPLAY; - const SHARED_CROSS_ADAPTER = d3d12::D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER; - const DENT_RT_DS_TEXTURES = d3d12::D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES; - const DENY_NON_RT_DS_TEXTURES = d3d12::D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES; - const HARDWARE_PROTECTED = d3d12::D3D12_HEAP_FLAG_HARDWARE_PROTECTED; - const ALLOW_WRITE_WATCH = d3d12::D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH; - const ALLOW_ALL_BUFFERS_AND_TEXTURES = d3d12::D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES; - const ALLOW_ONLY_BUFFERS = d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS; - const ALLOW_ONLY_NON_RT_DS_TEXTURES = d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES; - const ALLOW_ONLY_RT_DS_TEXTURES = d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES; - } -} - -#[repr(transparent)] -pub struct HeapProperties(pub d3d12::D3D12_HEAP_PROPERTIES); -impl HeapProperties { - pub fn new( - heap_type: HeapType, - cpu_page_property: CpuPageProperty, - memory_pool_preference: MemoryPool, - creation_node_mask: u32, - visible_node_mask: u32, - ) -> Self { - HeapProperties(d3d12::D3D12_HEAP_PROPERTIES { - Type: heap_type as _, - CPUPageProperty: cpu_page_property as _, - MemoryPoolPreference: memory_pool_preference as _, - CreationNodeMask: creation_node_mask, - VisibleNodeMask: visible_node_mask, - }) - } -} - -#[repr(transparent)] -pub struct HeapDesc(d3d12::D3D12_HEAP_DESC); -impl HeapDesc { - pub fn new( - size_in_bytes: u64, - properties: HeapProperties, - alignment: u64, - flags: HeapFlags, - ) -> Self { - HeapDesc(d3d12::D3D12_HEAP_DESC { - SizeInBytes: size_in_bytes, - Properties: properties.0, - Alignment: alignment, - Flags: flags.bits(), - }) - } -} diff --git a/d3d12/src/lib.rs b/d3d12/src/lib.rs deleted file mode 100644 index 13f0226891..0000000000 --- a/d3d12/src/lib.rs +++ /dev/null @@ -1,125 +0,0 @@ -#![cfg(windows)] -#![allow( - clippy::missing_safety_doc, - clippy::too_many_arguments, - clippy::not_unsafe_ptr_arg_deref -)] - -use std::{convert::TryFrom, ffi::CStr}; -use winapi::{ - shared::dxgiformat, - um::{d3d12, d3dcommon}, -}; - -mod com; -mod command_allocator; -mod command_list; -mod debug; -mod descriptor; -mod device; -mod dxgi; -mod heap; -mod pso; -mod query; -mod queue; -mod resource; -mod sync; - -pub use crate::com::*; -pub use crate::command_allocator::*; -pub use crate::command_list::*; -pub use crate::debug::*; -pub use crate::descriptor::*; -pub use crate::device::*; -pub use crate::dxgi::*; -pub use crate::heap::*; -pub use crate::pso::*; -pub use crate::query::*; -pub use crate::queue::*; -pub use crate::resource::*; -pub use crate::sync::*; - -pub use winapi::shared::winerror::HRESULT; - -pub type D3DResult = (T, HRESULT); -pub type GpuAddress = d3d12::D3D12_GPU_VIRTUAL_ADDRESS; -pub type Format = dxgiformat::DXGI_FORMAT; -pub type Rect = d3d12::D3D12_RECT; -pub type NodeMask = u32; - -/// Index into the root signature. -pub type RootIndex = u32; -/// Draw vertex count. -pub type VertexCount = u32; -/// Draw vertex base offset. -pub type VertexOffset = i32; -/// Draw number of indices. -pub type IndexCount = u32; -/// Draw number of instances. -pub type InstanceCount = u32; -/// Number of work groups. -pub type WorkGroupCount = [u32; 3]; - -pub type TextureAddressMode = [d3d12::D3D12_TEXTURE_ADDRESS_MODE; 3]; - -pub struct SampleDesc { - pub count: u32, - pub quality: u32, -} - -#[repr(u32)] -#[non_exhaustive] -pub enum FeatureLevel { - L9_1 = d3dcommon::D3D_FEATURE_LEVEL_9_1, - L9_2 = d3dcommon::D3D_FEATURE_LEVEL_9_2, - L9_3 = d3dcommon::D3D_FEATURE_LEVEL_9_3, - L10_0 = d3dcommon::D3D_FEATURE_LEVEL_10_0, - L10_1 = d3dcommon::D3D_FEATURE_LEVEL_10_1, - L11_0 = d3dcommon::D3D_FEATURE_LEVEL_11_0, - L11_1 = d3dcommon::D3D_FEATURE_LEVEL_11_1, - L12_0 = d3dcommon::D3D_FEATURE_LEVEL_12_0, - L12_1 = d3dcommon::D3D_FEATURE_LEVEL_12_1, -} - -impl TryFrom for FeatureLevel { - type Error = (); - - fn try_from(value: u32) -> Result { - Ok(match value { - d3dcommon::D3D_FEATURE_LEVEL_9_1 => Self::L9_1, - d3dcommon::D3D_FEATURE_LEVEL_9_2 => Self::L9_2, - d3dcommon::D3D_FEATURE_LEVEL_9_3 => Self::L9_3, - d3dcommon::D3D_FEATURE_LEVEL_10_0 => Self::L10_0, - d3dcommon::D3D_FEATURE_LEVEL_10_1 => Self::L10_1, - d3dcommon::D3D_FEATURE_LEVEL_11_0 => Self::L11_0, - d3dcommon::D3D_FEATURE_LEVEL_11_1 => Self::L11_1, - d3dcommon::D3D_FEATURE_LEVEL_12_0 => Self::L12_0, - d3dcommon::D3D_FEATURE_LEVEL_12_1 => Self::L12_1, - _ => return Err(()), - }) - } -} - -pub type Blob = ComPtr; - -pub type Error = ComPtr; -impl Error { - pub unsafe fn as_c_str(&self) -> &CStr { - debug_assert!(!self.is_null()); - let data = self.GetBufferPointer(); - CStr::from_ptr(data as *const _ as *const _) - } -} - -#[cfg(feature = "libloading")] -#[derive(Debug)] -pub struct D3D12Lib { - lib: libloading::Library, -} - -#[cfg(feature = "libloading")] -impl D3D12Lib { - pub fn new() -> Result { - unsafe { libloading::Library::new("d3d12.dll").map(|lib| D3D12Lib { lib }) } - } -} diff --git a/d3d12/src/pso.rs b/d3d12/src/pso.rs deleted file mode 100644 index 83a549621f..0000000000 --- a/d3d12/src/pso.rs +++ /dev/null @@ -1,182 +0,0 @@ -//! Pipeline state - -use crate::{com::ComPtr, Blob, D3DResult, Error}; -use std::{ - ffi::{self, c_void}, - marker::PhantomData, - ops::Deref, - ptr, -}; -use winapi::um::{d3d12, d3dcompiler}; - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct PipelineStateFlags: u32 { - const TOOL_DEBUG = d3d12::D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG; - } -} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct ShaderCompileFlags: u32 { - const DEBUG = d3dcompiler::D3DCOMPILE_DEBUG; - const SKIP_VALIDATION = d3dcompiler::D3DCOMPILE_SKIP_VALIDATION; - const SKIP_OPTIMIZATION = d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION; - const PACK_MATRIX_ROW_MAJOR = d3dcompiler::D3DCOMPILE_PACK_MATRIX_ROW_MAJOR; - const PACK_MATRIX_COLUMN_MAJOR = d3dcompiler::D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; - const PARTIAL_PRECISION = d3dcompiler::D3DCOMPILE_PARTIAL_PRECISION; - // TODO: add missing flags - } -} - -#[derive(Copy, Clone)] -pub struct Shader<'a>(d3d12::D3D12_SHADER_BYTECODE, PhantomData<&'a c_void>); -impl<'a> Shader<'a> { - pub fn null() -> Self { - Shader( - d3d12::D3D12_SHADER_BYTECODE { - BytecodeLength: 0, - pShaderBytecode: ptr::null(), - }, - PhantomData, - ) - } - - pub fn from_raw(data: &'a [u8]) -> Self { - Shader( - d3d12::D3D12_SHADER_BYTECODE { - BytecodeLength: data.len() as _, - pShaderBytecode: data.as_ptr() as _, - }, - PhantomData, - ) - } - - // `blob` may not be null. - pub fn from_blob(blob: &'a Blob) -> Self { - Shader( - d3d12::D3D12_SHADER_BYTECODE { - BytecodeLength: unsafe { blob.GetBufferSize() }, - pShaderBytecode: unsafe { blob.GetBufferPointer() }, - }, - PhantomData, - ) - } - - /// Compile a shader from raw HLSL. - /// - /// * `target`: example format: `ps_5_1`. - pub fn compile( - code: &[u8], - target: &ffi::CStr, - entry: &ffi::CStr, - flags: ShaderCompileFlags, - ) -> D3DResult<(Blob, Error)> { - let mut shader = Blob::null(); - let mut error = Error::null(); - - let hr = unsafe { - d3dcompiler::D3DCompile( - code.as_ptr() as *const _, - code.len(), - ptr::null(), // defines - ptr::null(), // include - ptr::null_mut(), - entry.as_ptr() as *const _, - target.as_ptr() as *const _, - flags.bits(), - 0, - shader.mut_void() as *mut *mut _, - error.mut_void() as *mut *mut _, - ) - }; - - ((shader, error), hr) - } -} - -impl<'a> Deref for Shader<'a> { - type Target = d3d12::D3D12_SHADER_BYTECODE; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Copy, Clone)] -pub struct CachedPSO<'a>(d3d12::D3D12_CACHED_PIPELINE_STATE, PhantomData<&'a c_void>); -impl<'a> CachedPSO<'a> { - pub fn null() -> Self { - CachedPSO( - d3d12::D3D12_CACHED_PIPELINE_STATE { - CachedBlobSizeInBytes: 0, - pCachedBlob: ptr::null(), - }, - PhantomData, - ) - } - - // `blob` may not be null. - pub fn from_blob(blob: &'a Blob) -> Self { - CachedPSO( - d3d12::D3D12_CACHED_PIPELINE_STATE { - CachedBlobSizeInBytes: unsafe { blob.GetBufferSize() }, - pCachedBlob: unsafe { blob.GetBufferPointer() }, - }, - PhantomData, - ) - } -} - -impl<'a> Deref for CachedPSO<'a> { - type Target = d3d12::D3D12_CACHED_PIPELINE_STATE; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -pub type PipelineState = ComPtr; - -#[repr(u32)] -pub enum Subobject { - RootSignature = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE, - VS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS, - PS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS, - DS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS, - HS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS, - GS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS, - CS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS, - StreamOutput = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT, - Blend = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND, - SampleMask = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK, - Rasterizer = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER, - DepthStencil = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL, - InputLayout = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT, - IBStripCut = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE, - PrimitiveTopology = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY, - RTFormats = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS, - DSFormat = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT, - SampleDesc = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC, - NodeMask = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK, - CachedPSO = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO, - Flags = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS, - DepthStencil1 = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, - // ViewInstancing = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING, -} - -/// Subobject of a pipeline stream description -#[repr(C)] -pub struct PipelineStateSubobject { - subobject_align: [usize; 0], // Subobjects must have the same alignment as pointers. - subobject_type: d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE, - subobject: T, -} - -impl PipelineStateSubobject { - pub fn new(subobject_type: Subobject, subobject: T) -> Self { - PipelineStateSubobject { - subobject_align: [], - subobject_type: subobject_type as _, - subobject, - } - } -} diff --git a/d3d12/src/query.rs b/d3d12/src/query.rs deleted file mode 100644 index 68901de942..0000000000 --- a/d3d12/src/query.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::com::ComPtr; -use winapi::um::d3d12; - -#[repr(u32)] -#[derive(Debug, Copy, Clone)] -pub enum QueryHeapType { - Occlusion = d3d12::D3D12_QUERY_HEAP_TYPE_OCCLUSION, - Timestamp = d3d12::D3D12_QUERY_HEAP_TYPE_TIMESTAMP, - PipelineStatistics = d3d12::D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS, - SOStatistics = d3d12::D3D12_QUERY_HEAP_TYPE_SO_STATISTICS, - // VideoDecodeStatistics = d3d12::D3D12_QUERY_HEAP_TYPE_VIDEO_DECODE_STATISTICS, - // CopyQueueTimestamp = d3d12::D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP, -} - -pub type QueryHeap = ComPtr; diff --git a/d3d12/src/queue.rs b/d3d12/src/queue.rs deleted file mode 100644 index a569344f3f..0000000000 --- a/d3d12/src/queue.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::{com::ComPtr, sync::Fence, CommandList, HRESULT}; -use winapi::um::d3d12; - -#[repr(u32)] -pub enum Priority { - Normal = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, - High = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_HIGH, - GlobalRealtime = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME, -} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub struct CommandQueueFlags: u32 { - const DISABLE_GPU_TIMEOUT = d3d12::D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT; - } -} - -pub type CommandQueue = ComPtr; - -impl CommandQueue { - pub fn execute_command_lists(&self, command_lists: &[CommandList]) { - let command_lists = command_lists - .iter() - .map(CommandList::as_mut_ptr) - .collect::>(); - unsafe { self.ExecuteCommandLists(command_lists.len() as _, command_lists.as_ptr()) } - } - - pub fn signal(&self, fence: &Fence, value: u64) -> HRESULT { - unsafe { self.Signal(fence.as_mut_ptr(), value) } - } -} diff --git a/d3d12/src/resource.rs b/d3d12/src/resource.rs deleted file mode 100644 index def01f4147..0000000000 --- a/d3d12/src/resource.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! GPU Resource - -use crate::{com::ComPtr, D3DResult, Rect}; -use std::{ops::Range, ptr}; -use winapi::um::d3d12; - -pub type Subresource = u32; - -pub struct DiscardRegion<'a> { - pub rects: &'a [Rect], - pub subregions: Range, -} - -pub type Resource = ComPtr; - -impl Resource { - pub fn map( - &self, - subresource: Subresource, - read_range: Option>, - ) -> D3DResult<*mut ()> { - let mut ptr = ptr::null_mut(); - let read_range = read_range.map(|r| d3d12::D3D12_RANGE { - Begin: r.start, - End: r.end, - }); - let read = match read_range { - Some(ref r) => r as *const _, - None => ptr::null(), - }; - let hr = unsafe { self.Map(subresource, read, &mut ptr) }; - - (ptr as _, hr) - } - - pub fn unmap(&self, subresource: Subresource, write_range: Option>) { - let write_range = write_range.map(|r| d3d12::D3D12_RANGE { - Begin: r.start, - End: r.end, - }); - let write = match write_range { - Some(ref r) => r as *const _, - None => ptr::null(), - }; - - unsafe { self.Unmap(subresource, write) }; - } - - pub fn gpu_virtual_address(&self) -> u64 { - unsafe { self.GetGPUVirtualAddress() } - } -} diff --git a/d3d12/src/sync.rs b/d3d12/src/sync.rs deleted file mode 100644 index fa5f090409..0000000000 --- a/d3d12/src/sync.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::{com::ComPtr, HRESULT}; -use std::ptr; -use winapi::um::{d3d12, synchapi, winnt}; - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct Event(pub winnt::HANDLE); -impl Event { - pub fn create(manual_reset: bool, initial_state: bool) -> Self { - Event(unsafe { - synchapi::CreateEventA( - ptr::null_mut(), - manual_reset as _, - initial_state as _, - ptr::null(), - ) - }) - } - - // TODO: return value - pub fn wait(&self, timeout_ms: u32) -> u32 { - unsafe { synchapi::WaitForSingleObject(self.0, timeout_ms) } - } -} - -pub type Fence = ComPtr; -impl Fence { - pub fn set_event_on_completion(&self, event: Event, value: u64) -> HRESULT { - unsafe { self.SetEventOnCompletion(value, event.0) } - } - - pub fn get_value(&self) -> u64 { - unsafe { self.GetCompletedValue() } - } - - pub fn signal(&self, value: u64) -> HRESULT { - unsafe { self.Signal(value) } - } -} diff --git a/deno_webgpu/bundle.rs b/deno_webgpu/bundle.rs index 0d1421d202..58d179051b 100644 --- a/deno_webgpu/bundle.rs +++ b/deno_webgpu/bundle.rs @@ -150,7 +150,7 @@ pub fn op_webgpu_render_bundle_encoder_set_bind_group( wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( &mut render_bundle_encoder_resource.0.borrow_mut(), index, - bind_group_resource.1, + Some(bind_group_resource.1), dynamic_offsets_data.as_ptr(), dynamic_offsets_data.len(), ); diff --git a/deno_webgpu/compute_pass.rs b/deno_webgpu/compute_pass.rs index e3e69860ab..6755e84a6a 100644 --- a/deno_webgpu/compute_pass.rs +++ b/deno_webgpu/compute_pass.rs @@ -136,7 +136,7 @@ pub fn op_webgpu_compute_pass_set_bind_group( .compute_pass_set_bind_group( &mut compute_pass_resource.0.borrow_mut(), index, - bind_group_resource.1, + Some(bind_group_resource.1), dynamic_offsets_data, )?; diff --git a/deno_webgpu/error.rs b/deno_webgpu/error.rs index feafbe3d74..caea7d9d81 100644 --- a/deno_webgpu/error.rs +++ b/deno_webgpu/error.rs @@ -68,6 +68,7 @@ pub struct WebGpuResult { } impl WebGpuResult { + #[must_use] pub fn rid(rid: ResourceId) -> Self { Self { rid: Some(rid), @@ -75,6 +76,7 @@ impl WebGpuResult { } } + #[must_use] pub fn rid_err>(rid: ResourceId, err: Option) -> Self { Self { rid: Some(rid), @@ -82,6 +84,7 @@ impl WebGpuResult { } } + #[must_use] pub fn maybe_err>(err: Option) -> Self { Self { rid: None, @@ -89,6 +92,7 @@ impl WebGpuResult { } } + #[must_use] pub fn empty() -> Self { Self { rid: None, @@ -307,6 +311,7 @@ pub struct DomExceptionOperationError { } impl DomExceptionOperationError { + #[must_use] pub fn new(msg: &str) -> Self { DomExceptionOperationError { msg: msg.to_string(), @@ -322,6 +327,7 @@ impl fmt::Display for DomExceptionOperationError { impl std::error::Error for DomExceptionOperationError {} +#[must_use] pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { e.downcast_ref::() .map(|_| "DOMExceptionOperationError") diff --git a/deno_webgpu/lib.rs b/deno_webgpu/lib.rs index c2dfb240fa..e31812e25f 100644 --- a/deno_webgpu/lib.rs +++ b/deno_webgpu/lib.rs @@ -401,10 +401,7 @@ pub fn op_webgpu_request_adapter( force_fallback_adapter, compatible_surface: None, // windowless }; - let res = instance.request_adapter( - &descriptor, - wgpu_core::instance::AdapterInputs::Mask(backends, |_| None), - ); + let res = instance.request_adapter(&descriptor, backends, None); let adapter = match res { Ok(adapter) => adapter, @@ -414,9 +411,9 @@ pub fn op_webgpu_request_adapter( }) } }; - let adapter_features = instance.adapter_features(adapter)?; + let adapter_features = instance.adapter_features(adapter); let features = deserialize_features(&adapter_features); - let adapter_limits = instance.adapter_limits(adapter)?; + let adapter_limits = instance.adapter_limits(adapter); let instance = instance.clone(); @@ -649,7 +646,7 @@ pub fn op_webgpu_request_device( memory_hints: wgpu_types::MemoryHints::default(), }; - let (device, queue, maybe_err) = instance.adapter_request_device( + let res = instance.adapter_request_device( adapter, &descriptor, std::env::var("DENO_WEBGPU_TRACE") @@ -660,13 +657,12 @@ pub fn op_webgpu_request_device( None, ); adapter_resource.close(); - if let Some(err) = maybe_err { - return Err(DomExceptionOperationError::new(&err.to_string()).into()); - } - let device_features = instance.device_features(device)?; + let (device, queue) = res.map_err(|err| DomExceptionOperationError::new(&err.to_string()))?; + + let device_features = instance.device_features(device); let features = deserialize_features(&device_features); - let limits = instance.device_limits(device)?; + let limits = instance.device_limits(device); let instance = instance.clone(); let instance2 = instance.clone(); @@ -705,7 +701,7 @@ pub fn op_webgpu_request_adapter_info( let adapter = adapter_resource.1; let instance = state.borrow::(); - let info = instance.adapter_get_info(adapter)?; + let info = instance.adapter_get_info(adapter); adapter_resource.close(); Ok(GPUAdapterInfo { diff --git a/deno_webgpu/render_pass.rs b/deno_webgpu/render_pass.rs index 2d4557cf03..4929fbbe90 100644 --- a/deno_webgpu/render_pass.rs +++ b/deno_webgpu/render_pass.rs @@ -231,7 +231,7 @@ pub fn op_webgpu_render_pass_set_bind_group( .render_pass_set_bind_group( &mut render_pass_resource.0.borrow_mut(), index, - bind_group_resource.1, + Some(bind_group_resource.1), dynamic_offsets_data, )?; diff --git a/examples/src/boids/mod.rs b/examples/src/boids/mod.rs index 8c3581824b..c527be96d9 100644 --- a/examples/src/boids/mod.rs +++ b/examples/src/boids/mod.rs @@ -2,7 +2,7 @@ // adapted from https://github.com/austinEng/webgpu-samples/blob/master/src/examples/computeBoids.ts use nanorand::{Rng, WyRand}; -use std::{borrow::Cow, mem}; +use std::{borrow::Cow, mem::size_of}; use wgpu::util::DeviceExt; // number of boid particles to simulate @@ -82,7 +82,7 @@ impl crate::framework::Example for Example { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: wgpu::BufferSize::new( - (sim_param_data.len() * mem::size_of::()) as _, + (sim_param_data.len() * size_of::()) as _, ), }, count: None, @@ -298,7 +298,7 @@ impl crate::framework::Example for Example { timestamp_writes: None, }); cpass.set_pipeline(&self.compute_pipeline); - cpass.set_bind_group(0, &self.particle_bind_groups[self.frame_num % 2], &[]); + cpass.set_bind_group(0, Some(&self.particle_bind_groups[self.frame_num % 2]), &[]); cpass.dispatch_workgroups(self.work_group_count, 1, 1); } command_encoder.pop_debug_group(); diff --git a/examples/src/bunnymark/mod.rs b/examples/src/bunnymark/mod.rs index 54bdc2a941..0c242c7137 100644 --- a/examples/src/bunnymark/mod.rs +++ b/examples/src/bunnymark/mod.rs @@ -34,19 +34,29 @@ impl Bunny { self.position[0] += self.velocity[0] * delta; self.position[1] += self.velocity[1] * delta; self.velocity[1] += GRAVITY * delta; + if (self.velocity[0] > 0.0 && self.position[0] + 0.5 * BUNNY_SIZE > extent[0] as f32) || (self.velocity[0] < 0.0 && self.position[0] - 0.5 * BUNNY_SIZE < 0.0) { self.velocity[0] *= -1.0; } + if self.velocity[1] < 0.0 && self.position[1] < 0.5 * BUNNY_SIZE { self.velocity[1] *= -1.0; } + + // Top boundary check + if self.velocity[1] > 0.0 && self.position[1] + 0.5 * BUNNY_SIZE > extent[1] as f32 { + self.velocity[1] *= -1.0; + } } } /// Example struct holds references to wgpu resources and frame persistent data struct Example { + view: wgpu::TextureView, + sampler: wgpu::Sampler, + global_bind_group_layout: wgpu::BindGroupLayout, global_group: wgpu::BindGroup, local_group: wgpu::BindGroup, pipeline: wgpu::RenderPipeline, @@ -118,11 +128,11 @@ impl Example { occlusion_query_set: None, }); rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.global_group, &[]); + rpass.set_bind_group(0, Some(&self.global_group), &[]); for i in 0..self.bunnies.len() { let offset = (i as wgpu::DynamicOffset) * (uniform_alignment as wgpu::DynamicOffset); - rpass.set_bind_group(1, &self.local_group, &[offset]); + rpass.set_bind_group(1, Some(&self.local_group), &[offset]); rpass.draw(0..4, 0..1); } } @@ -286,6 +296,7 @@ impl crate::framework::Example for Example { size: [BUNNY_SIZE; 2], pad: [0.0; 2], }; + let global_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("global"), contents: bytemuck::bytes_of(&globals), @@ -335,6 +346,9 @@ impl crate::framework::Example for Example { let rng = WyRand::new_seed(42); let mut ex = Example { + view, + sampler, + global_bind_group_layout, pipeline, global_group, local_group, @@ -366,11 +380,51 @@ impl crate::framework::Example for Example { fn resize( &mut self, - _sc_desc: &wgpu::SurfaceConfiguration, - _device: &wgpu::Device, + sc_desc: &wgpu::SurfaceConfiguration, + device: &wgpu::Device, _queue: &wgpu::Queue, ) { - //empty + self.extent = [sc_desc.width, sc_desc.height]; + + let globals = Globals { + mvp: glam::Mat4::orthographic_rh( + 0.0, + sc_desc.width as f32, + 0.0, + sc_desc.height as f32, + -1.0, + 1.0, + ) + .to_cols_array_2d(), + size: [BUNNY_SIZE; 2], + pad: [0.0; 2], + }; + + let global_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("global"), + contents: bytemuck::bytes_of(&globals), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM, + }); + + let global_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &self.global_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: global_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&self.view), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::Sampler(&self.sampler), + }, + ], + label: None, + }); + self.global_group = global_group; } fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) { diff --git a/examples/src/conservative_raster/mod.rs b/examples/src/conservative_raster/mod.rs index d029134756..46fb8742a0 100644 --- a/examples/src/conservative_raster/mod.rs +++ b/examples/src/conservative_raster/mod.rs @@ -305,7 +305,7 @@ impl crate::framework::Example for Example { }); rpass.set_pipeline(&self.pipeline_upscale); - rpass.set_bind_group(0, &self.bind_group_upscale, &[]); + rpass.set_bind_group(0, Some(&self.bind_group_upscale), &[]); rpass.draw(0..3, 0..1); if let Some(pipeline_lines) = &self.pipeline_lines { diff --git a/examples/src/cube/mod.rs b/examples/src/cube/mod.rs index 608fae0088..78dc06e061 100644 --- a/examples/src/cube/mod.rs +++ b/examples/src/cube/mod.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use std::{borrow::Cow, f32::consts, mem}; +use std::{borrow::Cow, f32::consts, mem::size_of}; use wgpu::util::DeviceExt; #[repr(C)] @@ -114,7 +114,7 @@ impl crate::framework::Example for Example { queue: &wgpu::Queue, ) -> Self { // Create the vertex and index buffers - let vertex_size = mem::size_of::(); + let vertex_size = size_of::(); let (vertex_data, index_data) = create_vertices(); let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { @@ -361,7 +361,7 @@ impl crate::framework::Example for Example { }); rpass.push_debug_group("Prepare data for draw."); rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint16); rpass.set_vertex_buffer(0, self.vertex_buf.slice(..)); rpass.pop_debug_group(); diff --git a/examples/src/hello_compute/mod.rs b/examples/src/hello_compute/mod.rs index 7f3c3f05bf..e53f49fa43 100644 --- a/examples/src/hello_compute/mod.rs +++ b/examples/src/hello_compute/mod.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, str::FromStr}; +use std::{borrow::Cow, mem::size_of_val, str::FromStr}; use wgpu::util::DeviceExt; // Indicates a u32 overflow in an intermediate Collatz value @@ -72,7 +72,7 @@ async fn execute_gpu_inner( }); // Gets the size in bytes of the buffer. - let size = std::mem::size_of_val(numbers) as wgpu::BufferAddress; + let size = size_of_val(numbers) as wgpu::BufferAddress; // Instantiates buffer without data. // `usage` of buffer specifies how it can be used: @@ -135,7 +135,7 @@ async fn execute_gpu_inner( timestamp_writes: None, }); cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.insert_debug_marker("compute collatz iterations"); cpass.dispatch_workgroups(numbers.len() as u32, 1, 1); // Number of cells to run, the (x,y,z) size of item being processed } diff --git a/examples/src/hello_synchronization/mod.rs b/examples/src/hello_synchronization/mod.rs index 397af48c98..fad5d7a9da 100644 --- a/examples/src/hello_synchronization/mod.rs +++ b/examples/src/hello_synchronization/mod.rs @@ -1,3 +1,5 @@ +use std::mem::size_of_val; + const ARR_SIZE: usize = 128; struct ExecuteResults { @@ -61,13 +63,13 @@ async fn execute( let storage_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: None, - size: std::mem::size_of_val(local_patient_workgroup_results.as_slice()) as u64, + size: size_of_val(local_patient_workgroup_results.as_slice()) as u64, usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC, mapped_at_creation: false, }); let output_staging_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: None, - size: std::mem::size_of_val(local_patient_workgroup_results.as_slice()) as u64, + size: size_of_val(local_patient_workgroup_results.as_slice()) as u64, usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, mapped_at_creation: false, }); @@ -126,7 +128,7 @@ async fn execute( timestamp_writes: None, }); compute_pass.set_pipeline(&patient_pipeline); - compute_pass.set_bind_group(0, &bind_group, &[]); + compute_pass.set_bind_group(0, Some(&bind_group), &[]); compute_pass.dispatch_workgroups(local_patient_workgroup_results.len() as u32, 1, 1); } queue.submit(Some(command_encoder.finish())); @@ -148,7 +150,7 @@ async fn execute( timestamp_writes: None, }); compute_pass.set_pipeline(&hasty_pipeline); - compute_pass.set_bind_group(0, &bind_group, &[]); + compute_pass.set_bind_group(0, Some(&bind_group), &[]); compute_pass.dispatch_workgroups(local_patient_workgroup_results.len() as u32, 1, 1); } queue.submit(Some(command_encoder.finish())); @@ -182,7 +184,7 @@ async fn get_data( 0, staging_buffer, 0, - std::mem::size_of_val(output) as u64, + size_of_val(output) as u64, ); queue.submit(Some(command_encoder.finish())); let buffer_slice = staging_buffer.slice(..); diff --git a/examples/src/hello_workgroups/mod.rs b/examples/src/hello_workgroups/mod.rs index 3260aa8628..7a653cf3e8 100644 --- a/examples/src/hello_workgroups/mod.rs +++ b/examples/src/hello_workgroups/mod.rs @@ -7,6 +7,8 @@ //! //! Only parts specific to this example will be commented. +use std::mem::size_of_val; + use wgpu::util::DeviceExt; async fn run() { @@ -56,7 +58,7 @@ async fn run() { }); let output_staging_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: None, - size: std::mem::size_of_val(&local_a) as u64, + size: size_of_val(&local_a) as u64, usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, mapped_at_creation: false, }); @@ -125,7 +127,7 @@ async fn run() { timestamp_writes: None, }); compute_pass.set_pipeline(&pipeline); - compute_pass.set_bind_group(0, &bind_group, &[]); + compute_pass.set_bind_group(0, Some(&bind_group), &[]); /* Note that since each workgroup will cover both arrays, we only need to cover the length of one array. */ compute_pass.dispatch_workgroups(local_a.len() as u32, 1, 1); @@ -169,7 +171,7 @@ async fn get_data( 0, staging_buffer, 0, - std::mem::size_of_val(output) as u64, + size_of_val(output) as u64, ); queue.submit(Some(command_encoder.finish())); let buffer_slice = staging_buffer.slice(..); diff --git a/examples/src/mipmap/mod.rs b/examples/src/mipmap/mod.rs index 33e23a474a..179970ad7f 100644 --- a/examples/src/mipmap/mod.rs +++ b/examples/src/mipmap/mod.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use std::{borrow::Cow, f32::consts, mem}; +use std::{borrow::Cow, f32::consts, mem::size_of}; use wgpu::util::DeviceExt; const TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8UnormSrgb; @@ -54,8 +54,7 @@ type TimestampQueries = [TimestampData; MIP_PASS_COUNT as usize]; type PipelineStatisticsQueries = [u64; MIP_PASS_COUNT as usize]; fn pipeline_statistics_offset() -> wgpu::BufferAddress { - (mem::size_of::() as wgpu::BufferAddress) - .max(wgpu::QUERY_RESOLVE_BUFFER_ALIGNMENT) + (size_of::() as wgpu::BufferAddress).max(wgpu::QUERY_RESOLVE_BUFFER_ALIGNMENT) } struct Example { @@ -181,7 +180,7 @@ impl Example { ); } rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.draw(0..3, 0..1); if let Some(ref query_sets) = query_sets { rpass.write_timestamp(&query_sets.timestamp, timestamp_query_index_base + 1); @@ -363,7 +362,7 @@ impl crate::framework::Example for Example { // This databuffer has to store all of the query results, 2 * passes timestamp queries // and 1 * passes statistics queries. Each query returns a u64 value. let buffer_size = pipeline_statistics_offset() - + mem::size_of::() as wgpu::BufferAddress; + + size_of::() as wgpu::BufferAddress; let data_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("query buffer"), size: buffer_size, @@ -420,7 +419,7 @@ impl crate::framework::Example for Example { // This is guaranteed to be ready. let timestamp_view = query_sets .mapping_buffer - .slice(..mem::size_of::() as wgpu::BufferAddress) + .slice(..size_of::() as wgpu::BufferAddress) .get_mapped_range(); let pipeline_stats_view = query_sets .mapping_buffer @@ -498,7 +497,7 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); rpass.set_pipeline(&self.draw_pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.draw(0..4, 0..1); } diff --git a/examples/src/msaa_line/mod.rs b/examples/src/msaa_line/mod.rs index e57a4461ab..431fe02bab 100644 --- a/examples/src/msaa_line/mod.rs +++ b/examples/src/msaa_line/mod.rs @@ -7,7 +7,7 @@ //! * Set the primitive_topology to PrimitiveTopology::LineList. //! * Vertices and Indices describe the two points that make up a line. -use std::{borrow::Cow, iter}; +use std::{borrow::Cow, iter, mem::size_of}; use bytemuck::{Pod, Zeroable}; use wgpu::util::DeviceExt; @@ -56,7 +56,7 @@ impl Example { entry_point: Some("vs_main"), compilation_options: Default::default(), buffers: &[wgpu::VertexBufferLayout { - array_stride: std::mem::size_of::() as wgpu::BufferAddress, + array_stride: size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x4], }], diff --git a/examples/src/ray_cube_compute/mod.rs b/examples/src/ray_cube_compute/mod.rs index 4d2c238844..4df478c10a 100644 --- a/examples/src/ray_cube_compute/mod.rs +++ b/examples/src/ray_cube_compute/mod.rs @@ -356,7 +356,7 @@ impl crate::framework::Example for Example { }); let blas_geo_size_desc = rt::BlasTriangleGeometrySizeDescriptor { - vertex_format: wgpu::VertexFormat::Float32x4, + vertex_format: wgpu::VertexFormat::Float32x3, vertex_count: vertex_data.len() as u32, index_format: Some(wgpu::IndexFormat::Uint16), index_count: Some(index_data.len() as u32), @@ -579,7 +579,7 @@ impl crate::framework::Example for Example { timestamp_writes: None, }); cpass.set_pipeline(&self.compute_pipeline); - cpass.set_bind_group(0, &self.compute_bind_group, &[]); + cpass.set_bind_group(0, Some(&self.compute_bind_group), &[]); cpass.dispatch_workgroups(self.rt_target.width() / 8, self.rt_target.height() / 8, 1); } @@ -600,7 +600,7 @@ impl crate::framework::Example for Example { }); rpass.set_pipeline(&self.blit_pipeline); - rpass.set_bind_group(0, &self.blit_bind_group, &[]); + rpass.set_bind_group(0, Some(&self.blit_bind_group), &[]); rpass.draw(0..3, 0..1); } diff --git a/examples/src/ray_cube_fragment/mod.rs b/examples/src/ray_cube_fragment/mod.rs index cfada8fd21..6da273b455 100644 --- a/examples/src/ray_cube_fragment/mod.rs +++ b/examples/src/ray_cube_fragment/mod.rs @@ -166,7 +166,7 @@ impl crate::framework::Example for Example { }); let blas_geo_size_desc = rt::BlasTriangleGeometrySizeDescriptor { - vertex_format: wgpu::VertexFormat::Float32x4, + vertex_format: wgpu::VertexFormat::Float32x3, vertex_count: vertex_data.len() as u32, index_format: Some(wgpu::IndexFormat::Uint16), index_count: Some(index_data.len() as u32), @@ -365,7 +365,7 @@ impl crate::framework::Example for Example { }); rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.draw(0..3, 0..1); } diff --git a/examples/src/ray_scene/mod.rs b/examples/src/ray_scene/mod.rs index 25f663d4bf..2423a2b52d 100644 --- a/examples/src/ray_scene/mod.rs +++ b/examples/src/ray_scene/mod.rs @@ -541,7 +541,7 @@ impl crate::framework::Example for Example { }); rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.draw(0..3, 0..1); } diff --git a/examples/src/repeated_compute/mod.rs b/examples/src/repeated_compute/mod.rs index 5dac9ce7c2..83dcd4099e 100644 --- a/examples/src/repeated_compute/mod.rs +++ b/examples/src/repeated_compute/mod.rs @@ -59,7 +59,7 @@ async fn compute(local_buffer: &mut [u32], context: &WgpuContext) { timestamp_writes: None, }); compute_pass.set_pipeline(&context.pipeline); - compute_pass.set_bind_group(0, &context.bind_group, &[]); + compute_pass.set_bind_group(0, Some(&context.bind_group), &[]); compute_pass.dispatch_workgroups(local_buffer.len() as u32, 1, 1); } // We finish the compute pass by dropping it. diff --git a/examples/src/shadow/mod.rs b/examples/src/shadow/mod.rs index 7047ab598c..a7edcce7e8 100644 --- a/examples/src/shadow/mod.rs +++ b/examples/src/shadow/mod.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, f32::consts, iter, mem, ops::Range, sync::Arc}; +use std::{borrow::Cow, f32::consts, iter, mem::size_of, ops::Range, sync::Arc}; use bytemuck::{Pod, Zeroable}; use wgpu::util::{align_to, DeviceExt}; @@ -219,7 +219,7 @@ impl crate::framework::Example for Example { && device.limits().max_storage_buffers_per_shader_stage > 0; // Create the vertex and index buffers - let vertex_size = mem::size_of::(); + let vertex_size = size_of::(); let (cube_vertex_data, cube_index_data) = create_cube(); let cube_vertex_buf = Arc::new(device.create_buffer_init( &wgpu::util::BufferInitDescriptor { @@ -283,7 +283,7 @@ impl crate::framework::Example for Example { }, ]; - let entity_uniform_size = mem::size_of::() as wgpu::BufferAddress; + let entity_uniform_size = size_of::() as wgpu::BufferAddress; let num_entities = 1 + cube_descs.len() as wgpu::BufferAddress; // Make the `uniform_alignment` >= `entity_uniform_size` and aligned to `min_uniform_buffer_offset_alignment`. let uniform_alignment = { @@ -427,8 +427,7 @@ impl crate::framework::Example for Example { target_view: shadow_target_views[1].take().unwrap(), }, ]; - let light_uniform_size = - (Self::MAX_LIGHTS * mem::size_of::()) as wgpu::BufferAddress; + let light_uniform_size = (Self::MAX_LIGHTS * size_of::()) as wgpu::BufferAddress; let light_storage_buf = device.create_buffer(&wgpu::BufferDescriptor { label: None, size: light_uniform_size, @@ -454,7 +453,7 @@ impl crate::framework::Example for Example { }); let shadow_pass = { - let uniform_size = mem::size_of::() as wgpu::BufferAddress; + let uniform_size = size_of::() as wgpu::BufferAddress; // Create pipeline layout let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -548,7 +547,7 @@ impl crate::framework::Example for Example { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: wgpu::BufferSize::new( - mem::size_of::() as _, + size_of::() as _, ), }, count: None, @@ -737,7 +736,7 @@ impl crate::framework::Example for Example { for (i, light) in self.lights.iter().enumerate() { queue.write_buffer( &self.light_storage_buf, - (i * mem::size_of::()) as wgpu::BufferAddress, + (i * size_of::()) as wgpu::BufferAddress, bytemuck::bytes_of(&light.to_raw()), ); } @@ -757,7 +756,7 @@ impl crate::framework::Example for Example { // let's just copy it over to the shadow uniform buffer. encoder.copy_buffer_to_buffer( &self.light_storage_buf, - (i * mem::size_of::()) as wgpu::BufferAddress, + (i * size_of::()) as wgpu::BufferAddress, &self.shadow_pass.uniform_buf, 0, 64, @@ -780,10 +779,10 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); pass.set_pipeline(&self.shadow_pass.pipeline); - pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]); + pass.set_bind_group(0, Some(&self.shadow_pass.bind_group), &[]); for entity in &self.entities { - pass.set_bind_group(1, &self.entity_bind_group, &[entity.uniform_offset]); + pass.set_bind_group(1, Some(&self.entity_bind_group), &[entity.uniform_offset]); pass.set_index_buffer(entity.index_buf.slice(..), entity.index_format); pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); @@ -824,10 +823,10 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); pass.set_pipeline(&self.forward_pass.pipeline); - pass.set_bind_group(0, &self.forward_pass.bind_group, &[]); + pass.set_bind_group(0, Some(&self.forward_pass.bind_group), &[]); for entity in &self.entities { - pass.set_bind_group(1, &self.entity_bind_group, &[entity.uniform_offset]); + pass.set_bind_group(1, Some(&self.entity_bind_group), &[entity.uniform_offset]); pass.set_index_buffer(entity.index_buf.slice(..), entity.index_format); pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); diff --git a/examples/src/skybox/mod.rs b/examples/src/skybox/mod.rs index fd5532e6d1..82e58ef6d5 100644 --- a/examples/src/skybox/mod.rs +++ b/examples/src/skybox/mod.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use std::{borrow::Cow, f32::consts}; +use std::{borrow::Cow, f32::consts, mem::size_of}; use wgpu::{util::DeviceExt, AstcBlock, AstcChannel}; const IMAGE_SIZE: u32 = 256; @@ -231,7 +231,7 @@ impl crate::framework::Example for Example { entry_point: Some("vs_entity"), compilation_options: Default::default(), buffers: &[wgpu::VertexBufferLayout { - array_stride: std::mem::size_of::() as wgpu::BufferAddress, + array_stride: size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3], }], @@ -451,7 +451,7 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.set_pipeline(&self.entity_pipeline); for entity in self.entities.iter() { diff --git a/examples/src/srgb_blend/mod.rs b/examples/src/srgb_blend/mod.rs index 63e5e79cb5..822d95d3c4 100644 --- a/examples/src/srgb_blend/mod.rs +++ b/examples/src/srgb_blend/mod.rs @@ -202,7 +202,7 @@ impl crate::framework::Example for Example { }); rpass.push_debug_group("Prepare data for draw."); rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint16); rpass.set_vertex_buffer(0, self.vertex_buf.slice(..)); rpass.pop_debug_group(); diff --git a/examples/src/stencil_triangles/mod.rs b/examples/src/stencil_triangles/mod.rs index d497eccc32..bb433af11c 100644 --- a/examples/src/stencil_triangles/mod.rs +++ b/examples/src/stencil_triangles/mod.rs @@ -1,6 +1,6 @@ use bytemuck::{Pod, Zeroable}; use std::borrow::Cow; -use std::mem; +use std::mem::size_of; use wgpu::util::DeviceExt; #[repr(C)] @@ -31,7 +31,7 @@ impl crate::framework::Example for Example { _queue: &wgpu::Queue, ) -> Self { // Create the vertex and index buffers - let vertex_size = mem::size_of::(); + let vertex_size = size_of::(); let outer_vertices = [vertex(-1.0, -1.0), vertex(1.0, -1.0), vertex(0.0, 1.0)]; let mask_vertices = [vertex(-0.5, 0.0), vertex(0.0, -1.0), vertex(0.5, 0.0)]; diff --git a/examples/src/storage_texture/mod.rs b/examples/src/storage_texture/mod.rs index 76b95d09dd..a687584196 100644 --- a/examples/src/storage_texture/mod.rs +++ b/examples/src/storage_texture/mod.rs @@ -14,6 +14,8 @@ //! A lot of things aren't explained here via comments. See hello-compute and //! repeated-compute for code that is more thoroughly commented. +use std::mem::size_of_val; + #[cfg(not(target_arch = "wasm32"))] use crate::utils::output_image_native; #[cfg(target_arch = "wasm32")] @@ -64,7 +66,7 @@ async fn run(_path: Option) { let storage_texture_view = storage_texture.create_view(&wgpu::TextureViewDescriptor::default()); let output_staging_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: None, - size: std::mem::size_of_val(&texture_data[..]) as u64, + size: size_of_val(&texture_data[..]) as u64, usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, mapped_at_creation: false, }); @@ -115,7 +117,7 @@ async fn run(_path: Option) { label: None, timestamp_writes: None, }); - compute_pass.set_bind_group(0, &bind_group, &[]); + compute_pass.set_bind_group(0, Some(&bind_group), &[]); compute_pass.set_pipeline(&pipeline); compute_pass.dispatch_workgroups(TEXTURE_DIMS.0 as u32, TEXTURE_DIMS.1 as u32, 1); } diff --git a/examples/src/texture_arrays/mod.rs b/examples/src/texture_arrays/mod.rs index 785b461802..8c81950e9a 100644 --- a/examples/src/texture_arrays/mod.rs +++ b/examples/src/texture_arrays/mod.rs @@ -1,5 +1,8 @@ use bytemuck::{Pod, Zeroable}; -use std::num::{NonZeroU32, NonZeroU64}; +use std::{ + mem::size_of, + num::{NonZeroU32, NonZeroU64}, +}; use wgpu::util::DeviceExt; #[repr(C)] @@ -124,7 +127,7 @@ impl crate::framework::Example for Example { println!("Using fragment entry point '{fragment_entry_point}'"); - let vertex_size = std::mem::size_of::(); + let vertex_size = size_of::(); let vertex_data = create_vertices(); let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Vertex Buffer"), @@ -388,12 +391,12 @@ impl crate::framework::Example for Example { rpass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); rpass.set_index_buffer(self.index_buffer.slice(..), self.index_format); if self.uniform_workaround { - rpass.set_bind_group(0, &self.bind_group, &[0]); + rpass.set_bind_group(0, Some(&self.bind_group), &[0]); rpass.draw_indexed(0..6, 0, 0..1); - rpass.set_bind_group(0, &self.bind_group, &[256]); + rpass.set_bind_group(0, Some(&self.bind_group), &[256]); rpass.draw_indexed(6..12, 0, 0..1); } else { - rpass.set_bind_group(0, &self.bind_group, &[0]); + rpass.set_bind_group(0, Some(&self.bind_group), &[0]); rpass.draw_indexed(0..12, 0, 0..1); } diff --git a/examples/src/timestamp_queries/mod.rs b/examples/src/timestamp_queries/mod.rs index 3edcd7b83c..2921ae4c85 100644 --- a/examples/src/timestamp_queries/mod.rs +++ b/examples/src/timestamp_queries/mod.rs @@ -5,7 +5,7 @@ //! * passing `wgpu::RenderPassTimestampWrites`/`wgpu::ComputePassTimestampWrites` during render/compute pass creation. //! This writes timestamps for the beginning and end of a given pass. //! (enabled with wgpu::Features::TIMESTAMP_QUERY) -//! * `wgpu::CommandEncoder::write_timestamp` writes a between any commands recorded on an encoder. +//! * `wgpu::CommandEncoder::write_timestamp` writes a timestamp between any commands recorded on an encoder. //! (enabled with wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS) //! * `wgpu::RenderPass/ComputePass::write_timestamp` writes a timestamp within commands of a render pass. //! Note that some GPU architectures do not support this. @@ -17,6 +17,8 @@ //! The period, i.e. the unit of time, of the timestamps in wgpu is undetermined and needs to be queried with `wgpu::Queue::get_timestamp_period` //! in order to get comparable results. +use std::mem::size_of; + use wgpu::util::DeviceExt; struct Queries { @@ -123,13 +125,13 @@ impl Queries { }), resolve_buffer: device.create_buffer(&wgpu::BufferDescriptor { label: Some("query resolve buffer"), - size: std::mem::size_of::() as u64 * num_queries, + size: size_of::() as u64 * num_queries, usage: wgpu::BufferUsages::COPY_SRC | wgpu::BufferUsages::QUERY_RESOLVE, mapped_at_creation: false, }), destination_buffer: device.create_buffer(&wgpu::BufferDescriptor { label: Some("query dest buffer"), - size: std::mem::size_of::() as u64 * num_queries, + size: size_of::() as u64 * num_queries, usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, mapped_at_creation: false, }), @@ -164,7 +166,7 @@ impl Queries { let timestamps = { let timestamp_view = self .destination_buffer - .slice(..(std::mem::size_of::() as wgpu::BufferAddress * self.num_queries)) + .slice(..(size_of::() as wgpu::BufferAddress * self.num_queries)) .get_mapped_range(); bytemuck::cast_slice(×tamp_view).to_vec() }; @@ -322,7 +324,7 @@ fn compute_pass( }); *next_unused_query += 2; cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups(1, 1, 1); if device .features() diff --git a/examples/src/uniform_values/mod.rs b/examples/src/uniform_values/mod.rs index f275853ba2..1ef58de09a 100644 --- a/examples/src/uniform_values/mod.rs +++ b/examples/src/uniform_values/mod.rs @@ -16,7 +16,7 @@ //! The usage of the uniform buffer within the shader itself is pretty self-explanatory given //! some understanding of WGSL. -use std::sync::Arc; +use std::{mem::size_of, sync::Arc}; // We won't bring StorageBuffer into scope as that might be too easy to confuse // with actual GPU-allocated WGPU storage buffers. use encase::ShaderType; @@ -132,7 +132,7 @@ impl WgpuContext { // (2) let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: None, - size: std::mem::size_of::() as u64, + size: size_of::() as u64, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); @@ -327,7 +327,11 @@ async fn run(event_loop: EventLoop<()>, window: Arc) { }); render_pass.set_pipeline(&wgpu_context_ref.pipeline); // (9) - render_pass.set_bind_group(0, &wgpu_context_ref.bind_group, &[]); + render_pass.set_bind_group( + 0, + Some(&wgpu_context_ref.bind_group), + &[], + ); render_pass.draw(0..3, 0..1); } wgpu_context_ref.queue.submit(Some(encoder.finish())); diff --git a/examples/src/water/mod.rs b/examples/src/water/mod.rs index 6b4943d45e..505f5707e5 100644 --- a/examples/src/water/mod.rs +++ b/examples/src/water/mod.rs @@ -3,7 +3,7 @@ mod point_gen; use bytemuck::{Pod, Zeroable}; use glam::Vec3; use nanorand::{Rng, WyRand}; -use std::{borrow::Cow, f32::consts, iter, mem}; +use std::{borrow::Cow, f32::consts, iter, mem::size_of}; use wgpu::util::DeviceExt; /// @@ -273,12 +273,12 @@ impl crate::framework::Example for Example { queue: &wgpu::Queue, ) -> Self { // Size of one water vertex - let water_vertex_size = mem::size_of::(); + let water_vertex_size = size_of::(); let water_vertices = point_gen::HexWaterMesh::generate(SIZE).generate_points(); // Size of one terrain vertex - let terrain_vertex_size = mem::size_of::(); + let terrain_vertex_size = size_of::(); // Noise generation let terrain_noise = noise::OpenSimplex::default(); @@ -359,7 +359,7 @@ impl crate::framework::Example for Example { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: wgpu::BufferSize::new( - mem::size_of::() as _, + size_of::() as _, ), }, count: None, @@ -415,7 +415,7 @@ impl crate::framework::Example for Example { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: wgpu::BufferSize::new( - mem::size_of::() as _, + size_of::() as _ ), }, count: None, @@ -440,21 +440,21 @@ impl crate::framework::Example for Example { let water_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { label: Some("Water Uniforms"), - size: mem::size_of::() as _, + size: size_of::() as _, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let terrain_normal_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { label: Some("Normal Terrain Uniforms"), - size: mem::size_of::() as _, + size: size_of::() as _, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let terrain_flipped_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { label: Some("Flipped Terrain Uniforms"), - size: mem::size_of::() as _, + size: size_of::() as _, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); @@ -630,7 +630,7 @@ impl crate::framework::Example for Example { multiview: None, }); encoder.set_pipeline(&terrain_pipeline); - encoder.set_bind_group(0, &terrain_flipped_bind_group, &[]); + encoder.set_bind_group(0, Some(&terrain_flipped_bind_group), &[]); encoder.set_vertex_buffer(0, terrain_vertex_buf.slice(..)); encoder.draw(0..terrain_vertices.len() as u32, 0..1); encoder.finish(&wgpu::RenderBundleDescriptor::default()) @@ -712,7 +712,7 @@ impl crate::framework::Example for Example { let (water_sin, water_cos) = ((self.current_frame as f32) / 600.0).sin_cos(); queue.write_buffer( &self.water_uniform_buf, - mem::size_of::<[f32; 16]>() as wgpu::BufferAddress * 2, + size_of::<[f32; 16]>() as wgpu::BufferAddress * 2, bytemuck::cast_slice(&[water_sin, water_cos]), ); @@ -784,7 +784,7 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); rpass.set_pipeline(&self.terrain_pipeline); - rpass.set_bind_group(0, &self.terrain_normal_bind_group, &[]); + rpass.set_bind_group(0, Some(&self.terrain_normal_bind_group), &[]); rpass.set_vertex_buffer(0, self.terrain_vertex_buf.slice(..)); rpass.draw(0..self.terrain_vertex_count as u32, 0..1); } @@ -811,7 +811,7 @@ impl crate::framework::Example for Example { }); rpass.set_pipeline(&self.water_pipeline); - rpass.set_bind_group(0, &self.water_bind_group, &[]); + rpass.set_bind_group(0, Some(&self.water_bind_group), &[]); rpass.set_vertex_buffer(0, self.water_vertex_buf.slice(..)); rpass.draw(0..self.water_vertex_count as u32, 0..1); } diff --git a/lock-analyzer/Cargo.toml b/lock-analyzer/Cargo.toml new file mode 100644 index 0000000000..20eaee0f80 --- /dev/null +++ b/lock-analyzer/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "lock-analyzer" +edition.workspace = true +rust-version.workspace = true +keywords.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +version.workspace = true +authors.workspace = true + +[dependencies] +ron.workspace = true +anyhow.workspace = true + +[dependencies.serde] +workspace = true +features = ["serde_derive"] diff --git a/lock-analyzer/src/main.rs b/lock-analyzer/src/main.rs new file mode 100644 index 0000000000..18f131ab8b --- /dev/null +++ b/lock-analyzer/src/main.rs @@ -0,0 +1,254 @@ +//! Analyzer for data produced by `wgpu-core`'s `observe_locks` feature. +//! +//! When `wgpu-core`'s `observe_locks` feature is enabled, if the +//! `WGPU_CORE_LOCK_OBSERVE_DIR` environment variable is set to the +//! path of an existing directory, then every thread that acquires a +//! lock in `wgpu-core` will write its own log file to that directory. +//! You can then run this program to read those files and summarize +//! the results. +//! +//! This program also consults the `WGPU_CORE_LOCK_OBSERVE_DIR` +//! environment variable to find the log files written by `wgpu-core`. +//! +//! See `wgpu_core/src/lock/observing.rs` for a general explanation of +//! this analysis. + +use std::sync::Arc; +use std::{ + collections::{btree_map::Entry, BTreeMap, BTreeSet, HashMap}, + fmt, + path::PathBuf, +}; + +use anyhow::{Context, Result}; + +fn main() -> Result<()> { + let mut ranks: BTreeMap = BTreeMap::default(); + + let Ok(dir) = std::env::var("WGPU_CORE_LOCK_OBSERVE_DIR") else { + eprintln!(concat!( + "Please set the `WGPU_CORE_LOCK_OBSERVE_DIR` environment variable\n", + "to the path of the directory containing the files written by\n", + "`wgpu-core`'s `observe_locks` feature." + )); + anyhow::bail!("`WGPU_CORE_LOCK_OBSERVE_DIR` environment variable is not set"); + }; + let entries = + std::fs::read_dir(&dir).with_context(|| format!("failed to read directory {dir}"))?; + for entry in entries { + let entry = entry.with_context(|| format!("failed to read directory entry from {dir}"))?; + let name = PathBuf::from(&entry.file_name()); + let Some(extension) = name.extension() else { + eprintln!("Ignoring {}", name.display()); + continue; + }; + if extension != "ron" { + eprintln!("Ignoring {}", name.display()); + continue; + } + + let contents = std::fs::read(entry.path()) + .with_context(|| format!("failed to read lock observations from {}", name.display()))?; + // The addresses of `&'static Location<'static>` values could + // vary from run to run. + let mut locations: HashMap> = HashMap::default(); + for line in contents.split(|&b| b == b'\n') { + if line.is_empty() { + continue; + } + let action = ron::de::from_bytes::(line) + .with_context(|| format!("Error parsing action from {}", name.display()))?; + match action { + Action::Location { + address, + file, + line, + column, + } => { + let file = match file.split_once("src/") { + Some((_, after)) => after.to_string(), + None => file, + }; + assert!(locations + .insert(address, Arc::new(Location { file, line, column })) + .is_none()); + } + Action::Rank { + bit, + member_name, + const_name, + } => match ranks.entry(bit) { + Entry::Occupied(occupied) => { + let rank = occupied.get(); + assert_eq!(rank.member_name, member_name); + assert_eq!(rank.const_name, const_name); + } + Entry::Vacant(vacant) => { + vacant.insert(Rank { + member_name, + const_name, + acquisitions: BTreeMap::default(), + }); + } + }, + Action::Acquisition { + older_rank, + older_location, + newer_rank, + newer_location, + } => { + let older_location = locations[&older_location].clone(); + let newer_location = locations[&newer_location].clone(); + ranks + .get_mut(&older_rank) + .unwrap() + .acquisitions + .entry(newer_rank) + .or_default() + .entry(older_location) + .or_default() + .insert(newer_location); + } + } + } + } + + for older_rank in ranks.values() { + if older_rank.is_leaf() { + // We'll print leaf locks separately, below. + continue; + } + println!( + " rank {} {:?} followed by {{", + older_rank.const_name, older_rank.member_name + ); + let mut acquired_any_leaf_locks = false; + let mut first_newer = true; + for (newer_rank, locations) in &older_rank.acquisitions { + // List acquisitions of leaf locks at the end. + if ranks[newer_rank].is_leaf() { + acquired_any_leaf_locks = true; + continue; + } + if !first_newer { + println!(); + } + for (older_location, newer_locations) in locations { + if newer_locations.len() == 1 { + for newer_loc in newer_locations { + println!(" // holding {older_location} while locking {newer_loc}"); + } + } else { + println!(" // holding {older_location} while locking:"); + for newer_loc in newer_locations { + println!(" // {newer_loc}"); + } + } + } + println!(" {},", ranks[newer_rank].const_name); + first_newer = false; + } + + if acquired_any_leaf_locks { + // We checked that older_rank isn't a leaf lock, so we + // must have printed something above. + if !first_newer { + println!(); + } + println!(" // leaf lock acquisitions:"); + for newer_rank in older_rank.acquisitions.keys() { + if !ranks[newer_rank].is_leaf() { + continue; + } + println!(" {},", ranks[newer_rank].const_name); + } + } + println!(" }};"); + println!(); + } + + for older_rank in ranks.values() { + if !older_rank.is_leaf() { + continue; + } + + println!( + " rank {} {:?} followed by {{ }};", + older_rank.const_name, older_rank.member_name + ); + } + + Ok(()) +} + +#[derive(Debug, serde::Deserialize)] +#[serde(deny_unknown_fields)] +enum Action { + /// A location that we will refer to in later actions. + Location { + address: LocationAddress, + file: String, + line: u32, + column: u32, + }, + + /// A lock rank that we will refer to in later actions. + Rank { + bit: u32, + member_name: String, + const_name: String, + }, + + /// An attempt to acquire a lock while holding another lock. + Acquisition { + /// The number of the already acquired lock's rank. + older_rank: u32, + + /// The source position at which we acquired it. Specifically, + /// its `Location`'s address, as an integer. + older_location: LocationAddress, + + /// The number of the rank of the lock we are acquiring. + newer_rank: u32, + + /// The source position at which we are acquiring it. + /// Specifically, its `Location`'s address, as an integer. + newer_location: LocationAddress, + }, +} + +/// The memory address at which the `Location` was stored in the +/// observed process. +/// +/// This is not `usize` because it does not represent an address in +/// this `lock-analyzer` process. We might generate logs on a 64-bit +/// machine and analyze them on a 32-bit machine. The `u64` type is a +/// reasonable universal type for addresses on any machine. +type LocationAddress = u64; + +struct Rank { + member_name: String, + const_name: String, + acquisitions: BTreeMap, +} + +impl Rank { + fn is_leaf(&self) -> bool { + self.acquisitions.is_empty() + } +} + +type LocationSet = BTreeMap, BTreeSet>>; + +#[derive(Eq, Ord, PartialEq, PartialOrd)] +struct Location { + file: String, + line: u32, + column: u32, +} + +impl fmt::Display for Location { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{}", self.file, self.line) + } +} diff --git a/naga-cli/src/bin/naga.rs b/naga-cli/src/bin/naga.rs index 002c6dd664..e28519cb06 100644 --- a/naga-cli/src/bin/naga.rs +++ b/naga-cli/src/bin/naga.rs @@ -326,6 +326,8 @@ trait PrettyResult { fn unwrap_pretty(self) -> Self::Target; } +#[cold] +#[inline(never)] fn print_err(error: &dyn Error) { eprint!("{error}"); @@ -463,6 +465,7 @@ fn run() -> anyhow::Result<()> { let Parsed { mut module, input_text, + language, } = parse_input(input_path, input, ¶ms)?; // Include debugging information if requested. @@ -475,6 +478,7 @@ fn run() -> anyhow::Result<()> { params.spv_out.debug_info = Some(naga::back::spv::DebugInfo { source_code: input_text, file_name: input_path, + language, }) } else { eprintln!( @@ -577,6 +581,7 @@ fn run() -> anyhow::Result<()> { struct Parsed { module: naga::Module, input_text: Option, + language: naga::back::spv::SourceLanguage, } fn parse_input(input_path: &Path, input: Vec, params: &Parameters) -> anyhow::Result { @@ -591,16 +596,26 @@ fn parse_input(input_path: &Path, input: Vec, params: &Parameters) -> anyhow .context("Unable to determine --input-kind from filename")?, }; - let (module, input_text) = match input_kind { - InputKind::Bincode => (bincode::deserialize(&input)?, None), - InputKind::SpirV => { - naga::front::spv::parse_u8_slice(&input, ¶ms.spv_in).map(|m| (m, None))? - } + Ok(match input_kind { + InputKind::Bincode => Parsed { + module: bincode::deserialize(&input)?, + input_text: None, + language: naga::back::spv::SourceLanguage::Unknown, + }, + InputKind::SpirV => Parsed { + module: naga::front::spv::parse_u8_slice(&input, ¶ms.spv_in)?, + input_text: None, + language: naga::back::spv::SourceLanguage::Unknown, + }, InputKind::Wgsl => { let input = String::from_utf8(input)?; let result = naga::front::wgsl::parse_str(&input); match result { - Ok(v) => (v, Some(input)), + Ok(v) => Parsed { + module: v, + input_text: Some(input), + language: naga::back::spv::SourceLanguage::WGSL, + }, Err(ref e) => { let message = anyhow!( "Could not parse WGSL:\n{}", @@ -629,8 +644,8 @@ fn parse_input(input_path: &Path, input: Vec, params: &Parameters) -> anyhow }; let input = String::from_utf8(input)?; let mut parser = naga::front::glsl::Frontend::default(); - ( - parser + Parsed { + module: parser .parse( &naga::front::glsl::Options { stage: shader_stage.0, @@ -647,12 +662,11 @@ fn parse_input(input_path: &Path, input: Vec, params: &Parameters) -> anyhow error.emit_to_writer_with_path(&mut writer, &input, filename); std::process::exit(1); }), - Some(input), - ) + input_text: Some(input), + language: naga::back::spv::SourceLanguage::GLSL, + } } - }; - - Ok(Parsed { module, input_text }) + }) } fn write_output( @@ -831,7 +845,11 @@ fn bulk_validate(args: Args, params: &Parameters) -> anyhow::Result<()> { let path = Path::new(&input_path); let input = fs::read(path)?; - let Parsed { module, input_text } = match parse_input(path, input, params) { + let Parsed { + module, + input_text, + language: _, + } = match parse_input(path, input, params) { Ok(parsed) => parsed, Err(error) => { invalid.push(input_path.clone()); diff --git a/naga/Cargo.toml b/naga/Cargo.toml index e8415a3bc3..ef66e1c5dc 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -77,11 +77,11 @@ indexmap.workspace = true log = "0.4" spirv = { version = "0.3", optional = true } thiserror.workspace = true -serde = { version = "1.0.206", features = ["derive"], optional = true } +serde = { version = "1.0.210", features = ["derive"], optional = true } petgraph = { version = "0.6", optional = true } pp-rs = { version = "0.2.1", optional = true } hexf-parse = { version = "0.2.1", optional = true } -unicode-xid = { version = "0.2.3", optional = true } +unicode-xid = { version = "0.2.5", optional = true } [build-dependencies] cfg_aliases.workspace = true @@ -89,6 +89,7 @@ cfg_aliases.workspace = true [dev-dependencies] diff = "0.1" env_logger.workspace = true +itertools.workspace = true # This _cannot_ have a version specified. If it does, crates.io will look # for a version of the package on crates when we publish naga. Path dependencies # are allowed through though. diff --git a/naga/hlsl-snapshots/src/lib.rs b/naga/hlsl-snapshots/src/lib.rs index 616aa73f01..ee45543273 100644 --- a/naga/hlsl-snapshots/src/lib.rs +++ b/naga/hlsl-snapshots/src/lib.rs @@ -53,6 +53,7 @@ pub struct Config { } impl Config { + #[must_use] pub fn empty() -> Self { Self { vertex: Default::default(), @@ -78,6 +79,7 @@ impl Config { fs::write(path, &s).map_err(|e| anyhow!("failed to write to {}: {e}", path.display())) } + #[must_use] pub fn is_empty(&self) -> bool { let Self { vertex, diff --git a/naga/src/back/glsl/features.rs b/naga/src/back/glsl/features.rs index b22bcbe651..362f4bb4f3 100644 --- a/naga/src/back/glsl/features.rs +++ b/naga/src/back/glsl/features.rs @@ -399,7 +399,7 @@ impl<'a, W> Writer<'a, W> { | StorageFormat::Rg16Float | StorageFormat::Rgb10a2Uint | StorageFormat::Rgb10a2Unorm - | StorageFormat::Rg11b10UFloat + | StorageFormat::Rg11b10Ufloat | StorageFormat::Rg32Uint | StorageFormat::Rg32Sint | StorageFormat::Rg32Float => { diff --git a/naga/src/back/glsl/mod.rs b/naga/src/back/glsl/mod.rs index 4c7f8b3251..159d9cdcf2 100644 --- a/naga/src/back/glsl/mod.rs +++ b/naga/src/back/glsl/mod.rs @@ -47,7 +47,7 @@ pub use features::Features; use crate::{ back::{self, Baked}, - proc::{self, NameKey}, + proc::{self, ExpressionKindTracker, NameKey}, valid, Handle, ShaderStage, TypeInner, }; use features::FeaturesManager; @@ -498,6 +498,9 @@ pub enum Error { Custom(String), #[error("overrides should not be present at this stage")] Override, + /// [`crate::Sampling::First`] is unsupported. + #[error("`{:?}` sampling is unsupported", crate::Sampling::First)] + FirstSamplingNotSupported, } /// Binary operation with a different logic on the GLSL side. @@ -1534,7 +1537,7 @@ impl<'a, W: Write> Writer<'a, W> { // here, regardless of the version. if let Some(sampling) = sampling { if emit_interpolation_and_auxiliary { - if let Some(qualifier) = glsl_sampling(sampling) { + if let Some(qualifier) = glsl_sampling(sampling)? { write!(self.out, "{qualifier} ")?; } } @@ -1584,6 +1587,7 @@ impl<'a, W: Write> Writer<'a, W> { info, expressions: &func.expressions, named_expressions: &func.named_expressions, + expr_kind_tracker: ExpressionKindTracker::from_arena(&func.expressions), }; self.named_expressions.clear(); @@ -4770,14 +4774,15 @@ const fn glsl_interpolation(interpolation: crate::Interpolation) -> &'static str } /// Return the GLSL auxiliary qualifier for the given sampling value. -const fn glsl_sampling(sampling: crate::Sampling) -> Option<&'static str> { +const fn glsl_sampling(sampling: crate::Sampling) -> BackendResult> { use crate::Sampling as S; - match sampling { - S::Center => None, + Ok(match sampling { + S::First => return Err(Error::FirstSamplingNotSupported), + S::Center | S::Either => None, S::Centroid => Some("centroid"), S::Sample => Some("sample"), - } + }) } /// Helper function that returns the glsl dimension string of [`ImageDimension`](crate::ImageDimension) @@ -4820,7 +4825,7 @@ fn glsl_storage_format(format: crate::StorageFormat) -> Result<&'static str, Err Sf::Rgba8Sint => "rgba8i", Sf::Rgb10a2Uint => "rgb10_a2ui", Sf::Rgb10a2Unorm => "rgb10_a2", - Sf::Rg11b10UFloat => "r11f_g11f_b10f", + Sf::Rg11b10Ufloat => "r11f_g11f_b10f", Sf::Rg32Uint => "rg32ui", Sf::Rg32Sint => "rg32i", Sf::Rg32Float => "rg32f", diff --git a/naga/src/back/hlsl/conv.rs b/naga/src/back/hlsl/conv.rs index 6c0daf4762..473fc9476d 100644 --- a/naga/src/back/hlsl/conv.rs +++ b/naga/src/back/hlsl/conv.rs @@ -119,38 +119,29 @@ impl crate::TypeInner { impl crate::StorageFormat { pub(super) const fn to_hlsl_str(self) -> &'static str { match self { - Self::R16Float => "float", + Self::R16Float | Self::R32Float => "float", Self::R8Unorm | Self::R16Unorm => "unorm float", Self::R8Snorm | Self::R16Snorm => "snorm float", - Self::R8Uint | Self::R16Uint => "uint", - Self::R8Sint | Self::R16Sint => "int", + Self::R8Uint | Self::R16Uint | Self::R32Uint => "uint", + Self::R8Sint | Self::R16Sint | Self::R32Sint => "int", - Self::Rg16Float => "float2", + Self::Rg16Float | Self::Rg32Float => "float2", Self::Rg8Unorm | Self::Rg16Unorm => "unorm float2", Self::Rg8Snorm | Self::Rg16Snorm => "snorm float2", - Self::Rg8Sint | Self::Rg16Sint => "int2", - Self::Rg8Uint | Self::Rg16Uint => "uint2", + Self::Rg8Sint | Self::Rg16Sint | Self::Rg32Uint => "int2", + Self::Rg8Uint | Self::Rg16Uint | Self::Rg32Sint => "uint2", - Self::Rg11b10UFloat => "float3", + Self::Rg11b10Ufloat => "float3", - Self::Rgba16Float | Self::R32Float | Self::Rg32Float | Self::Rgba32Float => "float4", + Self::Rgba16Float | Self::Rgba32Float => "float4", Self::Rgba8Unorm | Self::Bgra8Unorm | Self::Rgba16Unorm | Self::Rgb10a2Unorm => { "unorm float4" } Self::Rgba8Snorm | Self::Rgba16Snorm => "snorm float4", - Self::Rgba8Uint - | Self::Rgba16Uint - | Self::R32Uint - | Self::Rg32Uint - | Self::Rgba32Uint - | Self::Rgb10a2Uint => "uint4", - Self::Rgba8Sint - | Self::Rgba16Sint - | Self::R32Sint - | Self::Rg32Sint - | Self::Rgba32Sint => "int4", + Self::Rgba8Uint | Self::Rgba16Uint | Self::Rgba32Uint | Self::Rgb10a2Uint => "uint4", + Self::Rgba8Sint | Self::Rgba16Sint | Self::Rgba32Sint => "int4", } } } @@ -211,7 +202,7 @@ impl crate::Sampling { /// Return the HLSL auxiliary qualifier for the given sampling value. pub(super) const fn to_hlsl_str(self) -> Option<&'static str> { match self { - Self::Center => None, + Self::Center | Self::First | Self::Either => None, Self::Centroid => Some("centroid"), Self::Sample => Some("sample"), } diff --git a/naga/src/back/hlsl/writer.rs b/naga/src/back/hlsl/writer.rs index 85d943e850..e33fc79f20 100644 --- a/naga/src/back/hlsl/writer.rs +++ b/naga/src/back/hlsl/writer.rs @@ -8,7 +8,7 @@ use super::{ }; use crate::{ back::{self, Baked}, - proc::{self, NameKey}, + proc::{self, ExpressionKindTracker, NameKey}, valid, Handle, Module, Scalar, ScalarKind, ShaderStage, TypeInner, }; use std::{fmt, mem}; @@ -346,6 +346,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { info, expressions: &function.expressions, named_expressions: &function.named_expressions, + expr_kind_tracker: ExpressionKindTracker::from_arena(&function.expressions), }; let name = self.names[&NameKey::Function(handle)].clone(); @@ -386,6 +387,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { info, expressions: &ep.function.expressions, named_expressions: &ep.function.named_expressions, + expr_kind_tracker: ExpressionKindTracker::from_arena(&ep.function.expressions), }; self.write_wrapped_functions(module, &ctx)?; diff --git a/naga/src/back/mod.rs b/naga/src/back/mod.rs index 352adc37ec..58c7fa02cb 100644 --- a/naga/src/back/mod.rs +++ b/naga/src/back/mod.rs @@ -3,6 +3,8 @@ Backend functions that export shader [`Module`](super::Module)s into binary and */ #![allow(dead_code)] // can be dead if none of the enabled backends need it +use crate::proc::ExpressionKindTracker; + #[cfg(dot_out)] pub mod dot; #[cfg(glsl_out)] @@ -118,6 +120,8 @@ pub struct FunctionCtx<'a> { pub expressions: &'a crate::Arena, /// Map of expressions that have associated variable names pub named_expressions: &'a crate::NamedExpressions, + /// For constness checks + pub expr_kind_tracker: ExpressionKindTracker, } impl FunctionCtx<'_> { diff --git a/naga/src/back/msl/mod.rs b/naga/src/back/msl/mod.rs index 626475debc..96dd142a50 100644 --- a/naga/src/back/msl/mod.rs +++ b/naga/src/back/msl/mod.rs @@ -627,6 +627,7 @@ impl ResolvedInterpolation { (I::Linear, S::Centroid) => Self::CentroidNoPerspective, (I::Linear, S::Sample) => Self::SampleNoPerspective, (I::Flat, _) => Self::Flat, + _ => unreachable!(), } } diff --git a/naga/src/back/msl/writer.rs b/naga/src/back/msl/writer.rs index 48f862f8ba..e09ca557a9 100644 --- a/naga/src/back/msl/writer.rs +++ b/naga/src/back/msl/writer.rs @@ -6,6 +6,8 @@ use crate::{ proc::{self, NameKey, TypeResolution}, valid, FastHashMap, FastHashSet, }; +#[cfg(test)] +use std::ptr; use std::{ fmt::{Display, Error as FmtError, Formatter, Write}, iter, @@ -374,6 +376,11 @@ pub struct Writer { /// Set of (struct type, struct field index) denoting which fields require /// padding inserted **before** them (i.e. between fields at index - 1 and index) struct_member_pads: FastHashSet<(Handle, u32)>, + + /// Name of the loop reachability macro. + /// + /// See `emit_loop_reachable_macro` for details. + loop_reachable_macro_name: String, } impl crate::Scalar { @@ -663,6 +670,7 @@ impl Writer { #[cfg(test)] put_block_stack_pointers: Default::default(), struct_member_pads: FastHashSet::default(), + loop_reachable_macro_name: String::default(), } } @@ -673,6 +681,128 @@ impl Writer { self.out } + /// Define a macro to invoke before loops, to defeat MSL infinite loop + /// reasoning. + /// + /// If we haven't done so already, emit the definition of a preprocessor + /// macro to be invoked before each loop in the generated MSL, to ensure + /// that the MSL compiler's optimizations do not remove bounds checks. + /// + /// Only the first call to this function for a given module actually causes + /// the macro definition to be written. Subsequent loops can simply use the + /// prior macro definition, since macros aren't block-scoped. + /// + /// # What is this trying to solve? + /// + /// In Metal Shading Language, an infinite loop has undefined behavior. + /// (This rule is inherited from C++14.) This means that, if the MSL + /// compiler determines that a given loop will never exit, it may assume + /// that it is never reached. It may thus assume that any conditions + /// sufficient to cause the loop to be reached must be false. Like many + /// optimizing compilers, MSL uses this kind of analysis to establish limits + /// on the range of values variables involved in those conditions might + /// hold. + /// + /// For example, suppose the MSL compiler sees the code: + /// + /// ```ignore + /// if (i >= 10) { + /// while (true) { } + /// } + /// ``` + /// + /// It will recognize that the `while` loop will never terminate, conclude + /// that it must be unreachable, and thus infer that, if this code is + /// reached, then `i < 10` at that point. + /// + /// Now suppose that, at some point where `i` has the same value as above, + /// the compiler sees the code: + /// + /// ```ignore + /// if (i < 10) { + /// a[i] = 1; + /// } + /// ``` + /// + /// Because the compiler is confident that `i < 10`, it will make the + /// assignment to `a[i]` unconditional, rewriting this code as, simply: + /// + /// ```ignore + /// a[i] = 1; + /// ``` + /// + /// If that `if` condition was injected by Naga to implement a bounds check, + /// the MSL compiler's optimizations could allow out-of-bounds array + /// accesses to occur. + /// + /// Naga cannot feasibly anticipate whether the MSL compiler will determine + /// that a loop is infinite, so an attacker could craft a Naga module + /// containing an infinite loop protected by conditions that cause the Metal + /// compiler to remove bounds checks that Naga injected elsewhere in the + /// function. + /// + /// This rewrite could occur even if the conditional assignment appears + /// *before* the `while` loop, as long as `i < 10` by the time the loop is + /// reached. This would allow the attacker to save the results of + /// unauthorized reads somewhere accessible before entering the infinite + /// loop. But even worse, the MSL compiler has been observed to simply + /// delete the infinite loop entirely, so that even code dominated by the + /// loop becomes reachable. This would make the attack even more flexible, + /// since shaders that would appear to never terminate would actually exit + /// nicely, after having stolen data from elsewhere in the GPU address + /// space. + /// + /// Ideally, Naga would prevent UB entirely via some means that persuades + /// the MSL compiler that no loop Naga generates is infinite. One approach + /// would be to add inline assembly to each loop that is annotated as + /// potentially branching out of the loop, but which in fact generates no + /// instructions. Unfortunately, inline assembly is not handled correctly by + /// some Metal device drivers. Further experimentation hasn't produced a + /// satisfactory approach. + /// + /// Instead, we accept that the MSL compiler may determine that some loops + /// are infinite, and focus instead on preventing the range analysis from + /// being affected. We transform *every* loop into something like this: + /// + /// ```ignore + /// if (volatile bool unpredictable = true; unpredictable) + /// while (true) { } + /// ``` + /// + /// Since the `volatile` qualifier prevents the compiler from assuming that + /// the `if` condition is true, it cannot be sure the infinite loop is + /// reached, and thus it cannot assume the entire structure is unreachable. + /// This prevents the range analysis impact described above. + /// + /// Unfortunately, what makes this a kludge, not a hack, is that this + /// solution leaves the GPU executing a pointless conditional branch, at + /// runtime, before each loop. There's no part of the system that has a + /// global enough view to be sure that `unpredictable` is true, and remove + /// it from the code. + /// + /// To make our output a bit more legible, we pull the condition out into a + /// preprocessor macro defined at the top of the module. + /// + /// This approach is also used by Chromium WebGPU's Dawn shader compiler, as of + /// . + fn emit_loop_reachable_macro(&mut self) -> BackendResult { + if !self.loop_reachable_macro_name.is_empty() { + return Ok(()); + } + + self.loop_reachable_macro_name = self.namer.call("LOOP_IS_REACHABLE"); + let loop_reachable_volatile_name = self.namer.call("unpredictable_jump_over_loop"); + writeln!( + self.out, + "#define {} if (volatile bool {} = true; {})", + self.loop_reachable_macro_name, + loop_reachable_volatile_name, + loop_reachable_volatile_name, + )?; + + Ok(()) + } + fn put_call_parameters( &mut self, parameters: impl Iterator>, @@ -1411,9 +1541,8 @@ impl Writer { ) -> BackendResult { // Add to the set in order to track the stack size. #[cfg(test)] - #[allow(trivial_casts)] self.put_expression_stack_pointers - .insert(&expr_handle as *const _ as *const ()); + .insert(ptr::from_ref(&expr_handle).cast()); if let Some(name) = self.named_expressions.get(&expr_handle) { write!(self.out, "{name}")?; @@ -2792,9 +2921,8 @@ impl Writer { ) -> BackendResult { // Add to the set in order to track the stack size. #[cfg(test)] - #[allow(trivial_casts)] self.put_block_stack_pointers - .insert(&level as *const _ as *const ()); + .insert(ptr::from_ref(&level).cast()); for statement in statements { log::trace!("statement[{}] {:?}", level.0, statement); @@ -2924,10 +3052,15 @@ impl Writer { ref continuing, break_if, } => { + self.emit_loop_reachable_macro()?; if !continuing.is_empty() || break_if.is_some() { let gate_name = self.namer.call("loop_init"); writeln!(self.out, "{level}bool {gate_name} = true;")?; - writeln!(self.out, "{level}while(true) {{")?; + writeln!( + self.out, + "{level}{} while(true) {{", + self.loop_reachable_macro_name, + )?; let lif = level.next(); let lcontinuing = lif.next(); writeln!(self.out, "{lif}if (!{gate_name}) {{")?; @@ -2942,7 +3075,11 @@ impl Writer { writeln!(self.out, "{lif}}}")?; writeln!(self.out, "{lif}{gate_name} = false;")?; } else { - writeln!(self.out, "{level}while(true) {{")?; + writeln!( + self.out, + "{level}{} while(true) {{", + self.loop_reachable_macro_name, + )?; } self.put_block(level.next(), body, context)?; writeln!(self.out, "{level}}}")?; @@ -3379,6 +3516,7 @@ impl Writer { &[CLAMPED_LOD_LOAD_PREFIX], &mut self.names, ); + self.loop_reachable_macro_name.clear(); self.struct_member_pads.clear(); writeln!( diff --git a/naga/src/back/pipeline_constants.rs b/naga/src/back/pipeline_constants.rs index 77ee530be9..5f82862f72 100644 --- a/naga/src/back/pipeline_constants.rs +++ b/naga/src/back/pipeline_constants.rs @@ -289,6 +289,7 @@ fn process_function( &mut local_expression_kind_tracker, &mut emitter, &mut block, + false, ); for (old_h, mut expr, span) in expressions.drain() { diff --git a/naga/src/back/spv/instructions.rs b/naga/src/back/spv/instructions.rs index 9029c973de..9bd58508a1 100644 --- a/naga/src/back/spv/instructions.rs +++ b/naga/src/back/spv/instructions.rs @@ -1170,7 +1170,7 @@ impl From for spirv::ImageFormat { Sf::Bgra8Unorm => Self::Unknown, Sf::Rgb10a2Uint => Self::Rgb10a2ui, Sf::Rgb10a2Unorm => Self::Rgb10A2, - Sf::Rg11b10UFloat => Self::R11fG11fB10f, + Sf::Rg11b10Ufloat => Self::R11fG11fB10f, Sf::Rg32Uint => Self::Rg32ui, Sf::Rg32Sint => Self::Rg32i, Sf::Rg32Float => Self::Rg32f, diff --git a/naga/src/back/spv/mod.rs b/naga/src/back/spv/mod.rs index 91407561ab..32bd1fcecf 100644 --- a/naga/src/back/spv/mod.rs +++ b/naga/src/back/spv/mod.rs @@ -16,7 +16,7 @@ mod selection; mod subgroup; mod writer; -pub use spirv::Capability; +pub use spirv::{Capability, SourceLanguage}; use crate::arena::{Handle, HandleVec}; use crate::proc::{BoundsCheckPolicies, TypeResolution}; @@ -89,6 +89,7 @@ impl IdGenerator { pub struct DebugInfo<'a> { pub source_code: &'a str, pub file_name: &'a std::path::Path, + pub language: SourceLanguage, } /// A SPIR-V block to which we are still adding instructions. diff --git a/naga/src/back/spv/writer.rs b/naga/src/back/spv/writer.rs index d1c1e82a20..678dcb4246 100644 --- a/naga/src/back/spv/writer.rs +++ b/naga/src/back/spv/writer.rs @@ -1511,7 +1511,12 @@ impl Writer { } match sampling { // Center sampling is the default in SPIR-V. - None | Some(crate::Sampling::Center) => (), + None + | Some( + crate::Sampling::Center + | crate::Sampling::First + | crate::Sampling::Either, + ) => (), Some(crate::Sampling::Centroid) => { self.decorate(id, Decoration::Centroid, &[]); } @@ -1962,7 +1967,7 @@ impl Writer { source_file_id, }); self.debugs.append(&mut Instruction::source_auto_continued( - spirv::SourceLanguage::Unknown, + debug_info.language, 0, &debug_info_inner, )); diff --git a/naga/src/back/wgsl/writer.rs b/naga/src/back/wgsl/writer.rs index e5a5e5f647..0f2635eb0d 100644 --- a/naga/src/back/wgsl/writer.rs +++ b/naga/src/back/wgsl/writer.rs @@ -1,7 +1,7 @@ use super::Error; use crate::{ back::{self, Baked}, - proc::{self, NameKey}, + proc::{self, ExpressionKindTracker, NameKey}, valid, Handle, Module, ShaderStage, TypeInner, }; use std::fmt::Write; @@ -166,6 +166,7 @@ impl Writer { info: fun_info, expressions: &function.expressions, named_expressions: &function.named_expressions, + expr_kind_tracker: ExpressionKindTracker::from_arena(&function.expressions), }; // Write the function @@ -193,6 +194,7 @@ impl Writer { info: info.get_entry_point(index), expressions: &ep.function.expressions, named_expressions: &ep.function.named_expressions, + expr_kind_tracker: ExpressionKindTracker::from_arena(&ep.function.expressions), }; self.write_function(module, &ep.function, &func_ctx)?; @@ -1115,8 +1117,14 @@ impl Writer { func_ctx: &back::FunctionCtx, name: &str, ) -> BackendResult { + // Some functions are marked as const, but are not yet implemented as constant expression + let quantifier = if func_ctx.expr_kind_tracker.is_impl_const(handle) { + "const" + } else { + "let" + }; // Write variable name - write!(self.out, "let {name}")?; + write!(self.out, "{quantifier} {name}")?; if self.flags.contains(WriterFlags::EXPLICIT_TYPES) { write!(self.out, ": ")?; let ty = &func_ctx.info[handle].ty; @@ -2015,7 +2023,7 @@ const fn storage_format_str(format: crate::StorageFormat) -> &'static str { Sf::Bgra8Unorm => "bgra8unorm", Sf::Rgb10a2Uint => "rgb10a2uint", Sf::Rgb10a2Unorm => "rgb10a2unorm", - Sf::Rg11b10UFloat => "rg11b10float", + Sf::Rg11b10Ufloat => "rg11b10float", Sf::Rg32Uint => "rg32uint", Sf::Rg32Sint => "rg32sint", Sf::Rg32Float => "rg32float", @@ -2053,6 +2061,8 @@ const fn sampling_str(sampling: crate::Sampling) -> &'static str { S::Center => "", S::Centroid => "centroid", S::Sample => "sample", + S::First => "first", + S::Either => "either", } } diff --git a/naga/src/front/atomic_upgrade.rs b/naga/src/front/atomic_upgrade.rs index c59969ace9..d2fbc12893 100644 --- a/naga/src/front/atomic_upgrade.rs +++ b/naga/src/front/atomic_upgrade.rs @@ -44,12 +44,8 @@ pub enum Error { MultiMemberStruct, #[error("encountered unsupported global initializer in an atomic variable")] GlobalInitUnsupported, -} - -impl From for crate::front::spv::Error { - fn from(source: Error) -> Self { - crate::front::spv::Error::AtomicUpgradeError(source) - } + #[error("expected to find a global variable")] + GlobalVariableMissing, } #[derive(Clone, Default)] diff --git a/naga/src/front/glsl/parser/types.rs b/naga/src/front/glsl/parser/types.rs index d22387f375..829b9fd897 100644 --- a/naga/src/front/glsl/parser/types.rs +++ b/naga/src/front/glsl/parser/types.rs @@ -397,7 +397,7 @@ fn map_image_format(word: &str) -> Option { "rgba16f" => Sf::Rgba16Float, "rg32f" => Sf::Rg32Float, "rg16f" => Sf::Rg16Float, - "r11f_g11f_b10f" => Sf::Rg11b10UFloat, + "r11f_g11f_b10f" => Sf::Rg11b10Ufloat, "r32f" => Sf::R32Float, "r16f" => Sf::R16Float, "rgba16" => Sf::Rgba16Unorm, diff --git a/naga/src/front/spv/convert.rs b/naga/src/front/spv/convert.rs index 88d171b5b7..f131db616e 100644 --- a/naga/src/front/spv/convert.rs +++ b/naga/src/front/spv/convert.rs @@ -104,7 +104,7 @@ pub(super) fn map_image_format(word: spirv::Word) -> Result Ok(crate::StorageFormat::Rgba8Sint), Some(spirv::ImageFormat::Rgb10a2ui) => Ok(crate::StorageFormat::Rgb10a2Uint), Some(spirv::ImageFormat::Rgb10A2) => Ok(crate::StorageFormat::Rgb10a2Unorm), - Some(spirv::ImageFormat::R11fG11fB10f) => Ok(crate::StorageFormat::Rg11b10UFloat), + Some(spirv::ImageFormat::R11fG11fB10f) => Ok(crate::StorageFormat::Rg11b10Ufloat), Some(spirv::ImageFormat::Rg32ui) => Ok(crate::StorageFormat::Rg32Uint), Some(spirv::ImageFormat::Rg32i) => Ok(crate::StorageFormat::Rg32Sint), Some(spirv::ImageFormat::Rg32f) => Ok(crate::StorageFormat::Rg32Float), diff --git a/naga/src/front/spv/error.rs b/naga/src/front/spv/error.rs index 42df9d807b..bcbb47ddeb 100644 --- a/naga/src/front/spv/error.rs +++ b/naga/src/front/spv/error.rs @@ -159,3 +159,9 @@ impl Error { String::from_utf8(writer.into_inner()).unwrap() } } + +impl From for Error { + fn from(source: atomic_upgrade::Error) -> Self { + crate::front::spv::Error::AtomicUpgradeError(source) + } +} diff --git a/naga/src/front/spv/mod.rs b/naga/src/front/spv/mod.rs index 7dfb4ae293..5ad063a6b6 100644 --- a/naga/src/front/spv/mod.rs +++ b/naga/src/front/spv/mod.rs @@ -565,11 +565,15 @@ impl<'a> BlockContext<'a> { /// Descend into the expression with the given handle, locating a contained /// global variable. /// + /// If the expression doesn't actually refer to something in a global + /// variable, we can't upgrade its type in a way that Naga validation would + /// pass, so reject the input instead. + /// /// This is used to track atomic upgrades. fn get_contained_global_variable( &self, mut handle: Handle, - ) -> Option> { + ) -> Result, Error> { log::debug!("\t\tlocating global variable in {handle:?}"); loop { match self.expressions[handle] { @@ -583,14 +587,16 @@ impl<'a> BlockContext<'a> { } crate::Expression::GlobalVariable(h) => { log::debug!("\t\t found {h:?}"); - return Some(h); + return Ok(h); } _ => { break; } } } - None + Err(Error::AtomicUpgradeError( + crate::front::atomic_upgrade::Error::GlobalVariableMissing, + )) } } @@ -1323,6 +1329,109 @@ impl> Frontend { )) } + /// Return the Naga [`Expression`] for `pointer_id`, and its referent [`Type`]. + /// + /// Return a [`Handle`] for a Naga [`Expression`] that holds the value of + /// the SPIR-V instruction `pointer_id`, along with the [`Type`] to which it + /// is a pointer. + /// + /// This may entail spilling `pointer_id`'s value to a temporary: + /// see [`get_expr_handle`]'s documentation. + /// + /// [`Expression`]: crate::Expression + /// [`Type`]: crate::Type + /// [`Handle`]: crate::Handle + /// [`get_expr_handle`]: Frontend::get_expr_handle + fn get_exp_and_base_ty_handles( + &self, + pointer_id: spirv::Word, + ctx: &mut BlockContext, + emitter: &mut crate::proc::Emitter, + block: &mut crate::Block, + body_idx: usize, + ) -> Result<(Handle, Handle), Error> { + log::trace!("\t\t\tlooking up pointer expr {:?}", pointer_id); + let p_lexp_handle; + let p_lexp_ty_id; + { + let lexp = self.lookup_expression.lookup(pointer_id)?; + p_lexp_handle = self.get_expr_handle(pointer_id, lexp, ctx, emitter, block, body_idx); + p_lexp_ty_id = lexp.type_id; + }; + + log::trace!("\t\t\tlooking up pointer type {pointer_id:?}"); + let p_ty = self.lookup_type.lookup(p_lexp_ty_id)?; + let p_ty_base_id = p_ty.base_id.ok_or(Error::InvalidAccessType(p_lexp_ty_id))?; + + log::trace!("\t\t\tlooking up pointer base type {p_ty_base_id:?} of {p_ty:?}"); + let p_base_ty = self.lookup_type.lookup(p_ty_base_id)?; + + Ok((p_lexp_handle, p_base_ty.handle)) + } + + #[allow(clippy::too_many_arguments)] + fn parse_atomic_expr_with_value( + &mut self, + inst: Instruction, + emitter: &mut crate::proc::Emitter, + ctx: &mut BlockContext, + block: &mut crate::Block, + block_id: spirv::Word, + body_idx: usize, + atomic_function: crate::AtomicFunction, + ) -> Result<(), Error> { + inst.expect(7)?; + let start = self.data_offset; + let result_type_id = self.next()?; + let result_id = self.next()?; + let pointer_id = self.next()?; + let _scope_id = self.next()?; + let _memory_semantics_id = self.next()?; + let value_id = self.next()?; + let span = self.span_from_with_op(start); + + let (p_lexp_handle, p_base_ty_handle) = + self.get_exp_and_base_ty_handles(pointer_id, ctx, emitter, block, body_idx)?; + + log::trace!("\t\t\tlooking up value expr {value_id:?}"); + let v_lexp_handle = self.lookup_expression.lookup(value_id)?.handle; + + block.extend(emitter.finish(ctx.expressions)); + // Create an expression for our result + let r_lexp_handle = { + let expr = crate::Expression::AtomicResult { + ty: p_base_ty_handle, + comparison: false, + }; + let handle = ctx.expressions.append(expr, span); + self.lookup_expression.insert( + result_id, + LookupExpression { + handle, + type_id: result_type_id, + block_id, + }, + ); + handle + }; + emitter.start(ctx.expressions); + + // Create a statement for the op itself + let stmt = crate::Statement::Atomic { + pointer: p_lexp_handle, + fun: atomic_function, + value: v_lexp_handle, + result: Some(r_lexp_handle), + }; + block.push(stmt, span); + + // Store any associated global variables so we can upgrade their types later + self.upgrade_atomics + .insert(ctx.get_contained_global_variable(p_lexp_handle)?); + + Ok(()) + } + /// Add the next SPIR-V block's contents to `block_ctx`. /// /// Except for the function's entry block, `block_id` should be the label of @@ -3985,35 +4094,91 @@ impl> Frontend { ); emitter.start(ctx.expressions); } - Op::AtomicIIncrement => { + Op::AtomicLoad => { inst.expect(6)?; let start = self.data_offset; - let span = self.span_from_with_op(start); let result_type_id = self.next()?; let result_id = self.next()?; let pointer_id = self.next()?; let _scope_id = self.next()?; let _memory_semantics_id = self.next()?; + let span = self.span_from_with_op(start); log::trace!("\t\t\tlooking up expr {:?}", pointer_id); - let (p_lexp_handle, p_lexp_ty_id) = { - let lexp = self.lookup_expression.lookup(pointer_id)?; - let handle = get_expr_handle!(pointer_id, &lexp); - (handle, lexp.type_id) + let p_lexp_handle = + get_expr_handle!(pointer_id, self.lookup_expression.lookup(pointer_id)?); + + // Create an expression for our result + let expr = crate::Expression::Load { + pointer: p_lexp_handle, + }; + let handle = ctx.expressions.append(expr, span); + self.lookup_expression.insert( + result_id, + LookupExpression { + handle, + type_id: result_type_id, + block_id, + }, + ); + + // Store any associated global variables so we can upgrade their types later + self.upgrade_atomics + .insert(ctx.get_contained_global_variable(p_lexp_handle)?); + } + Op::AtomicStore => { + inst.expect(5)?; + let start = self.data_offset; + let pointer_id = self.next()?; + let _scope_id = self.next()?; + let _memory_semantics_id = self.next()?; + let value_id = self.next()?; + let span = self.span_from_with_op(start); + + log::trace!("\t\t\tlooking up pointer expr {:?}", pointer_id); + let p_lexp_handle = + get_expr_handle!(pointer_id, self.lookup_expression.lookup(pointer_id)?); + + log::trace!("\t\t\tlooking up value expr {:?}", pointer_id); + let v_lexp_handle = + get_expr_handle!(value_id, self.lookup_expression.lookup(value_id)?); + + block.extend(emitter.finish(ctx.expressions)); + // Create a statement for the op itself + let stmt = crate::Statement::Store { + pointer: p_lexp_handle, + value: v_lexp_handle, }; + block.push(stmt, span); + emitter.start(ctx.expressions); - log::trace!("\t\t\tlooking up type {pointer_id:?}"); - let p_ty = self.lookup_type.lookup(p_lexp_ty_id)?; - let p_ty_base_id = - p_ty.base_id.ok_or(Error::InvalidAccessType(p_lexp_ty_id))?; + // Store any associated global variables so we can upgrade their types later + self.upgrade_atomics + .insert(ctx.get_contained_global_variable(p_lexp_handle)?); + } + Op::AtomicIIncrement | Op::AtomicIDecrement => { + inst.expect(6)?; + let start = self.data_offset; + let result_type_id = self.next()?; + let result_id = self.next()?; + let pointer_id = self.next()?; + let _scope_id = self.next()?; + let _memory_semantics_id = self.next()?; + let span = self.span_from_with_op(start); - log::trace!("\t\t\tlooking up base type {p_ty_base_id:?} of {p_ty:?}"); - let p_base_ty = self.lookup_type.lookup(p_ty_base_id)?; + let (p_exp_h, p_base_ty_h) = self.get_exp_and_base_ty_handles( + pointer_id, + ctx, + &mut emitter, + &mut block, + body_idx, + )?; + block.extend(emitter.finish(ctx.expressions)); // Create an expression for our result let r_lexp_handle = { let expr = crate::Expression::AtomicResult { - ty: p_base_ty.handle, + ty: p_base_ty_h, comparison: false, }; let handle = ctx.expressions.append(expr, span); @@ -4027,22 +4192,26 @@ impl> Frontend { ); handle }; + emitter.start(ctx.expressions); - // Create a literal "1" since WGSL lacks an increment operation + // Create a literal "1" to use as our value let one_lexp_handle = make_index_literal( ctx, 1, &mut block, &mut emitter, - p_base_ty.handle, - p_lexp_ty_id, + p_base_ty_h, + result_type_id, span, )?; // Create a statement for the op itself let stmt = crate::Statement::Atomic { - pointer: p_lexp_handle, - fun: crate::AtomicFunction::Add, + pointer: p_exp_h, + fun: match inst.op { + Op::AtomicIIncrement => crate::AtomicFunction::Add, + _ => crate::AtomicFunction::Subtract, + }, value: one_lexp_handle, result: Some(r_lexp_handle), }; @@ -4050,8 +4219,38 @@ impl> Frontend { // Store any associated global variables so we can upgrade their types later self.upgrade_atomics - .extend(ctx.get_contained_global_variable(p_lexp_handle)); + .insert(ctx.get_contained_global_variable(p_exp_h)?); } + Op::AtomicExchange + | Op::AtomicIAdd + | Op::AtomicISub + | Op::AtomicSMin + | Op::AtomicUMin + | Op::AtomicSMax + | Op::AtomicUMax + | Op::AtomicAnd + | Op::AtomicOr + | Op::AtomicXor => self.parse_atomic_expr_with_value( + inst, + &mut emitter, + ctx, + &mut block, + block_id, + body_idx, + match inst.op { + Op::AtomicExchange => crate::AtomicFunction::Exchange { compare: None }, + Op::AtomicIAdd => crate::AtomicFunction::Add, + Op::AtomicISub => crate::AtomicFunction::Subtract, + Op::AtomicSMin => crate::AtomicFunction::Min, + Op::AtomicUMin => crate::AtomicFunction::Min, + Op::AtomicSMax => crate::AtomicFunction::Max, + Op::AtomicUMax => crate::AtomicFunction::Max, + Op::AtomicAnd => crate::AtomicFunction::And, + Op::AtomicOr => crate::AtomicFunction::InclusiveOr, + _ => crate::AtomicFunction::ExclusiveOr, + }, + )?, + _ => { return Err(Error::UnsupportedInstruction(self.state, inst.op)); } @@ -5709,33 +5908,48 @@ mod test { ]; let _ = super::parse_u8_slice(&bin, &Default::default()).unwrap(); } +} - #[cfg(all(feature = "wgsl-in", wgsl_out))] - #[test] - fn atomic_i_inc() { +#[cfg(all(test, feature = "wgsl-in", wgsl_out))] +mod test_atomic { + fn atomic_test(bytes: &[u8]) { let _ = env_logger::builder().is_test(true).try_init(); - let bytes = include_bytes!("../../../tests/in/spv/atomic_i_increment.spv"); - let m = super::parse_u8_slice(bytes, &Default::default()).unwrap(); - let mut validator = crate::valid::Validator::new( + let m = crate::front::spv::parse_u8_slice(bytes, &Default::default()).unwrap(); + + let mut wgsl = String::new(); + let mut should_panic = false; + + for vflags in [ + crate::valid::ValidationFlags::all(), crate::valid::ValidationFlags::empty(), - Default::default(), - ); - let info = match validator.validate(&m) { - Err(e) => { - log::error!("{}", e.emit_to_string("")); - return; - } - Ok(i) => i, - }; - let wgsl = - crate::back::wgsl::write_string(&m, &info, crate::back::wgsl::WriterFlags::empty()) - .unwrap(); - log::info!("atomic_i_increment:\n{wgsl}"); + ] { + let mut validator = crate::valid::Validator::new(vflags, Default::default()); + match validator.validate(&m) { + Err(e) => { + log::error!("SPIR-V validation {}", e.emit_to_string("")); + should_panic = true; + } + Ok(i) => { + wgsl = crate::back::wgsl::write_string( + &m, + &i, + crate::back::wgsl::WriterFlags::empty(), + ) + .unwrap(); + log::info!("wgsl-out:\n{wgsl}"); + break; + } + }; + } + + if should_panic { + panic!("validation error"); + } let m = match crate::front::wgsl::parse_str(&wgsl) { Ok(m) => m, Err(e) => { - log::error!("{}", e.emit_to_string(&wgsl)); + log::error!("round trip WGSL validation {}", e.emit_to_string(&wgsl)); panic!("invalid module"); } }; @@ -5746,4 +5960,35 @@ mod test { panic!("invalid generated wgsl"); } } + + #[test] + fn atomic_i_inc() { + atomic_test(include_bytes!( + "../../../tests/in/spv/atomic_i_increment.spv" + )); + } + + #[test] + fn atomic_load_and_store() { + atomic_test(include_bytes!( + "../../../tests/in/spv/atomic_load_and_store.spv" + )); + } + + #[test] + fn atomic_exchange() { + atomic_test(include_bytes!("../../../tests/in/spv/atomic_exchange.spv")); + } + + #[test] + fn atomic_i_decrement() { + atomic_test(include_bytes!( + "../../../tests/in/spv/atomic_i_decrement.spv" + )); + } + + #[test] + fn atomic_i_add_and_sub() { + atomic_test(include_bytes!("../../../tests/in/spv/atomic_i_add_sub.spv")); + } } diff --git a/naga/src/front/wgsl/error.rs b/naga/src/front/wgsl/error.rs index febcd9a4e0..3d4ac62183 100644 --- a/naga/src/front/wgsl/error.rs +++ b/naga/src/front/wgsl/error.rs @@ -10,6 +10,9 @@ use std::ops::Range; use termcolor::{ColorChoice, NoColor, StandardStream}; use thiserror::Error; +#[cfg(test)] +use std::mem::size_of; + #[derive(Clone, Debug)] pub struct ParseError { message: String, @@ -144,7 +147,7 @@ pub enum InvalidAssignmentType { } #[derive(Clone, Debug)] -pub enum Error<'a> { +pub(crate) enum Error<'a> { Unexpected(Span, ExpectedToken<'a>), UnexpectedComponents(Span), UnexpectedOperationInConstContext(Span), @@ -154,8 +157,8 @@ pub enum Error<'a> { BadTexture(Span), BadTypeCast { span: Span, - from_type: String, - to_type: String, + from_type: Box, + to_type: Box, }, BadTextureSampleType { span: Span, @@ -188,8 +191,8 @@ pub enum Error<'a> { TypeNotInferable(Span), InitializationTypeMismatch { name: Span, - expected: String, - got: String, + expected: Box, + got: Box, }, DeclMissingTypeAndInit(Span), MissingAttribute(&'static str, Span), @@ -232,7 +235,7 @@ pub enum Error<'a> { /// name is `decl` has an identifier at `reference` whose definition is /// the next declaration in the cycle. The last pair's `reference` is /// the same identifier as `ident`, above. - path: Vec<(Span, Span)>, + path: Box<[(Span, Span)]>, }, InvalidSwitchValue { uint: bool, @@ -251,33 +254,46 @@ pub enum Error<'a> { ExpectedNonNegative(Span), ExpectedPositiveArrayLength(Span), MissingWorkgroupSize(Span), - ConstantEvaluatorError(ConstantEvaluatorError, Span), - AutoConversion { - dest_span: Span, - dest_type: String, - source_span: Span, - source_type: String, - }, - AutoConversionLeafScalar { - dest_span: Span, - dest_scalar: String, - source_span: Span, - source_type: String, - }, - ConcretizationFailed { - expr_span: Span, - expr_type: String, - scalar: String, - inner: ConstantEvaluatorError, - }, + ConstantEvaluatorError(Box, Span), + AutoConversion(Box), + AutoConversionLeafScalar(Box), + ConcretizationFailed(Box), ExceededLimitForNestedBraces { span: Span, limit: u8, }, PipelineConstantIDValue(Span), + NotBool(Span), + ConstAssertFailed(Span), +} + +#[derive(Clone, Debug)] +pub(crate) struct AutoConversionError { + pub dest_span: Span, + pub dest_type: Box, + pub source_span: Span, + pub source_type: Box, +} + +#[derive(Clone, Debug)] +pub(crate) struct AutoConversionLeafScalarError { + pub dest_span: Span, + pub dest_scalar: Box, + pub source_span: Span, + pub source_type: Box, +} + +#[derive(Clone, Debug)] +pub(crate) struct ConcretizationFailedError { + pub expr_span: Span, + pub expr_type: Box, + pub scalar: Box, + pub inner: ConstantEvaluatorError, } impl<'a> Error<'a> { + #[cold] + #[inline(never)] pub(crate) fn as_parse_error(&self, source: &'a str) -> ParseError { match *self { Error::Unexpected(unexpected_span, expected) => { @@ -736,45 +752,55 @@ impl<'a> Error<'a> { )], notes: vec![], }, - Error::AutoConversion { dest_span, ref dest_type, source_span, ref source_type } => ParseError { - message: format!("automatic conversions cannot convert `{source_type}` to `{dest_type}`"), - labels: vec![ - ( - dest_span, - format!("a value of type {dest_type} is required here").into(), - ), - ( - source_span, - format!("this expression has type {source_type}").into(), - ) - ], - notes: vec![], + Error::AutoConversion(ref error) => { + // destructuring ensures all fields are handled + let AutoConversionError { dest_span, ref dest_type, source_span, ref source_type } = **error; + ParseError { + message: format!("automatic conversions cannot convert `{source_type}` to `{dest_type}`"), + labels: vec![ + ( + dest_span, + format!("a value of type {dest_type} is required here").into(), + ), + ( + source_span, + format!("this expression has type {source_type}").into(), + ) + ], + notes: vec![], + } }, - Error::AutoConversionLeafScalar { dest_span, ref dest_scalar, source_span, ref source_type } => ParseError { - message: format!("automatic conversions cannot convert elements of `{source_type}` to `{dest_scalar}`"), - labels: vec![ - ( - dest_span, - format!("a value with elements of type {dest_scalar} is required here").into(), - ), - ( - source_span, - format!("this expression has type {source_type}").into(), - ) - ], - notes: vec![], + Error::AutoConversionLeafScalar(ref error) => { + let AutoConversionLeafScalarError { dest_span, ref dest_scalar, source_span, ref source_type } = **error; + ParseError { + message: format!("automatic conversions cannot convert elements of `{source_type}` to `{dest_scalar}`"), + labels: vec![ + ( + dest_span, + format!("a value with elements of type {dest_scalar} is required here").into(), + ), + ( + source_span, + format!("this expression has type {source_type}").into(), + ) + ], + notes: vec![], + } }, - Error::ConcretizationFailed { expr_span, ref expr_type, ref scalar, ref inner } => ParseError { - message: format!("failed to convert expression to a concrete type: {}", inner), - labels: vec![ - ( - expr_span, - format!("this expression has type {}", expr_type).into(), - ) - ], - notes: vec![ - format!("the expression should have been converted to have {} scalar type", scalar), - ] + Error::ConcretizationFailed(ref error) => { + let ConcretizationFailedError { expr_span, ref expr_type, ref scalar, ref inner } = **error; + ParseError { + message: format!("failed to convert expression to a concrete type: {}", inner), + labels: vec![ + ( + expr_span, + format!("this expression has type {}", expr_type).into(), + ) + ], + notes: vec![ + format!("the expression should have been converted to have {} scalar type", scalar), + ] + } }, Error::ExceededLimitForNestedBraces { span, limit } => ParseError { message: "brace nesting limit reached".into(), @@ -791,6 +817,27 @@ impl<'a> Error<'a> { )], notes: vec![], }, + Error::NotBool(span) => ParseError { + message: "must be a const-expression that resolves to a bool".to_string(), + labels: vec![( + span, + "must resolve to bool".into(), + )], + notes: vec![], + }, + Error::ConstAssertFailed(span) => ParseError { + message: "const_assert failure".to_string(), + labels: vec![( + span, + "evaluates to false".into(), + )], + notes: vec![], + }, } } } + +#[test] +fn test_error_size() { + assert!(size_of::>() <= 48); +} diff --git a/naga/src/front/wgsl/index.rs b/naga/src/front/wgsl/index.rs index 593405508f..bc0af670ff 100644 --- a/naga/src/front/wgsl/index.rs +++ b/naga/src/front/wgsl/index.rs @@ -20,13 +20,16 @@ impl<'a> Index<'a> { // While doing so, reject conflicting definitions. let mut globals = FastHashMap::with_capacity_and_hasher(tu.decls.len(), Default::default()); for (handle, decl) in tu.decls.iter() { - let ident = decl_ident(decl); - let name = ident.name; - if let Some(old) = globals.insert(name, handle) { - return Err(Error::Redefinition { - previous: decl_ident(&tu.decls[old]).span, - current: ident.span, - }); + if let Some(ident) = decl_ident(decl) { + let name = ident.name; + if let Some(old) = globals.insert(name, handle) { + return Err(Error::Redefinition { + previous: decl_ident(&tu.decls[old]) + .expect("decl should have ident for redefinition") + .span, + current: ident.span, + }); + } } } @@ -130,7 +133,7 @@ impl<'a> DependencySolver<'a, '_> { return if dep_id == id { // A declaration refers to itself directly. Err(Error::RecursiveDeclaration { - ident: decl_ident(decl).span, + ident: decl_ident(decl).expect("decl should have ident").span, usage: dep.usage, }) } else { @@ -146,14 +149,19 @@ impl<'a> DependencySolver<'a, '_> { .unwrap_or(0); Err(Error::CyclicDeclaration { - ident: decl_ident(&self.module.decls[dep_id]).span, + ident: decl_ident(&self.module.decls[dep_id]) + .expect("decl should have ident") + .span, path: self.path[start_at..] .iter() .map(|curr_dep| { let curr_id = curr_dep.decl; let curr_decl = &self.module.decls[curr_id]; - (decl_ident(curr_decl).span, curr_dep.usage) + ( + decl_ident(curr_decl).expect("decl should have ident").span, + curr_dep.usage, + ) }) .collect(), }) @@ -182,13 +190,14 @@ impl<'a> DependencySolver<'a, '_> { } } -const fn decl_ident<'a>(decl: &ast::GlobalDecl<'a>) -> ast::Ident<'a> { +const fn decl_ident<'a>(decl: &ast::GlobalDecl<'a>) -> Option> { match decl.kind { - ast::GlobalDeclKind::Fn(ref f) => f.name, - ast::GlobalDeclKind::Var(ref v) => v.name, - ast::GlobalDeclKind::Const(ref c) => c.name, - ast::GlobalDeclKind::Override(ref o) => o.name, - ast::GlobalDeclKind::Struct(ref s) => s.name, - ast::GlobalDeclKind::Type(ref t) => t.name, + ast::GlobalDeclKind::Fn(ref f) => Some(f.name), + ast::GlobalDeclKind::Var(ref v) => Some(v.name), + ast::GlobalDeclKind::Const(ref c) => Some(c.name), + ast::GlobalDeclKind::Override(ref o) => Some(o.name), + ast::GlobalDeclKind::Struct(ref s) => Some(s.name), + ast::GlobalDeclKind::Type(ref t) => Some(t.name), + ast::GlobalDeclKind::ConstAssert(_) => None, } } diff --git a/naga/src/front/wgsl/lower/construction.rs b/naga/src/front/wgsl/lower/construction.rs index de0d11d227..dff2e9d6e4 100644 --- a/naga/src/front/wgsl/lower/construction.rs +++ b/naga/src/front/wgsl/lower/construction.rs @@ -530,11 +530,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { // Bad conversion (type cast) (Components::One { span, ty_inner, .. }, constructor) => { - let from_type = ty_inner.to_wgsl(&ctx.module.to_ctx()); + let from_type = ty_inner.to_wgsl(&ctx.module.to_ctx()).into(); return Err(Error::BadTypeCast { span, from_type, - to_type: constructor.to_error_string(ctx), + to_type: constructor.to_error_string(ctx).into(), }); } @@ -578,8 +578,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { Constructor::Type(ty) } ast::ConstructorType::PartialVector { size } => Constructor::PartialVector { size }, - ast::ConstructorType::Vector { size, scalar } => { - let ty = ctx.ensure_type_exists(scalar.to_inner_vector(size)); + ast::ConstructorType::Vector { size, ty, ty_span } => { + let ty = self.resolve_ast_type(ty, &mut ctx.as_global())?; + let scalar = match ctx.module.types[ty].inner { + crate::TypeInner::Scalar(sc) => sc, + _ => return Err(Error::UnknownScalarType(ty_span)), + }; + let ty = ctx.ensure_type_exists(crate::TypeInner::Vector { size, scalar }); Constructor::Type(ty) } ast::ConstructorType::PartialMatrix { columns, rows } => { @@ -588,13 +593,22 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ast::ConstructorType::Matrix { rows, columns, - width, + ty, + ty_span, } => { - let ty = ctx.ensure_type_exists(crate::TypeInner::Matrix { - columns, - rows, - scalar: crate::Scalar::float(width), - }); + let ty = self.resolve_ast_type(ty, &mut ctx.as_global())?; + let scalar = match ctx.module.types[ty].inner { + crate::TypeInner::Scalar(sc) => sc, + _ => return Err(Error::UnknownScalarType(ty_span)), + }; + let ty = match scalar.kind { + crate::ScalarKind::Float => ctx.ensure_type_exists(crate::TypeInner::Matrix { + columns, + rows, + scalar, + }), + _ => return Err(Error::BadMatrixScalarKind(ty_span, scalar)), + }; Constructor::Type(ty) } ast::ConstructorType::PartialArray => Constructor::PartialArray, diff --git a/naga/src/front/wgsl/lower/conversion.rs b/naga/src/front/wgsl/lower/conversion.rs index 2a2690f096..0b2f884639 100644 --- a/naga/src/front/wgsl/lower/conversion.rs +++ b/naga/src/front/wgsl/lower/conversion.rs @@ -1,5 +1,8 @@ //! WGSL's automatic conversions for abstract types. +use crate::front::wgsl::error::{ + AutoConversionError, AutoConversionLeafScalarError, ConcretizationFailedError, +}; use crate::{Handle, Span}; impl<'source, 'temp, 'out> super::ExpressionContext<'source, 'temp, 'out> { @@ -39,15 +42,17 @@ impl<'source, 'temp, 'out> super::ExpressionContext<'source, 'temp, 'out> { Some(scalars) => scalars, None => { let gctx = &self.module.to_ctx(); - let source_type = expr_resolution.to_wgsl(gctx); - let dest_type = goal_ty.to_wgsl(gctx); - - return Err(super::Error::AutoConversion { - dest_span: goal_span, - dest_type, - source_span: expr_span, - source_type, - }); + let source_type = expr_resolution.to_wgsl(gctx).into(); + let dest_type = goal_ty.to_wgsl(gctx).into(); + + return Err(super::Error::AutoConversion(Box::new( + AutoConversionError { + dest_span: goal_span, + dest_type, + source_span: expr_span, + source_type, + }, + ))); } }; @@ -79,13 +84,13 @@ impl<'source, 'temp, 'out> super::ExpressionContext<'source, 'temp, 'out> { let make_error = || { let gctx = &self.module.to_ctx(); - let source_type = expr_resolution.to_wgsl(gctx); - super::Error::AutoConversionLeafScalar { + let source_type = expr_resolution.to_wgsl(gctx).into(); + super::Error::AutoConversionLeafScalar(Box::new(AutoConversionLeafScalarError { dest_span: goal_span, - dest_scalar: goal_scalar.to_wgsl(), + dest_scalar: goal_scalar.to_wgsl().into(), source_span: expr_span, source_type, - } + })) }; let expr_scalar = match expr_inner.scalar() { @@ -116,7 +121,7 @@ impl<'source, 'temp, 'out> super::ExpressionContext<'source, 'temp, 'out> { if let crate::TypeInner::Array { .. } = *expr_inner { self.as_const_evaluator() .cast_array(expr, goal_scalar, expr_span) - .map_err(|err| super::Error::ConstantEvaluatorError(err, expr_span)) + .map_err(|err| super::Error::ConstantEvaluatorError(err.into(), expr_span)) } else { let cast = crate::Expression::As { expr, @@ -254,12 +259,12 @@ impl<'source, 'temp, 'out> super::ExpressionContext<'source, 'temp, 'out> { // it has one. Also, avoid holding the borrow of `inner` // across the call to `cast_array`. let expr_type = &self.typifier()[expr]; - super::Error::ConcretizationFailed { + super::Error::ConcretizationFailed(Box::new(ConcretizationFailedError { expr_span, - expr_type: expr_type.to_wgsl(&self.module.to_ctx()), - scalar: concretized.to_wgsl(), + expr_type: expr_type.to_wgsl(&self.module.to_ctx()).into(), + scalar: concretized.to_wgsl().into(), inner: err, - } + })) })?; } } diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index 34f8daf506..7586f98dc3 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -98,7 +98,7 @@ impl<'source> GlobalContext<'source, '_, '_> { types: self.types, module: self.module, const_typifier: self.const_typifier, - expr_type: ExpressionContextType::Constant, + expr_type: ExpressionContextType::Constant(None), global_expression_kind_tracker: self.global_expression_kind_tracker, } } @@ -160,7 +160,8 @@ pub struct StatementContext<'source, 'temp, 'out> { /// /// [`LocalVariable`]: crate::Expression::LocalVariable /// [`FunctionArgument`]: crate::Expression::FunctionArgument - local_table: &'temp mut FastHashMap, Typed>>, + local_table: + &'temp mut FastHashMap, Declared>>>, const_typifier: &'temp mut Typifier, typifier: &'temp mut Typifier, @@ -184,6 +185,32 @@ pub struct StatementContext<'source, 'temp, 'out> { } impl<'a, 'temp> StatementContext<'a, 'temp, '_> { + fn as_const<'t>( + &'t mut self, + block: &'t mut crate::Block, + emitter: &'t mut Emitter, + ) -> ExpressionContext<'a, 't, '_> + where + 'temp: 't, + { + ExpressionContext { + globals: self.globals, + types: self.types, + ast_expressions: self.ast_expressions, + const_typifier: self.const_typifier, + global_expression_kind_tracker: self.global_expression_kind_tracker, + module: self.module, + expr_type: ExpressionContextType::Constant(Some(LocalExpressionContext { + local_table: self.local_table, + function: self.function, + block, + emitter, + typifier: self.typifier, + local_expression_kind_tracker: self.local_expression_kind_tracker, + })), + } + } + fn as_expression<'t>( &'t mut self, block: &'t mut crate::Block, @@ -199,7 +226,7 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> { const_typifier: self.const_typifier, global_expression_kind_tracker: self.global_expression_kind_tracker, module: self.module, - expr_type: ExpressionContextType::Runtime(RuntimeExpressionContext { + expr_type: ExpressionContextType::Runtime(LocalExpressionContext { local_table: self.local_table, function: self.function, block, @@ -235,12 +262,12 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> { } } -pub struct RuntimeExpressionContext<'temp, 'out> { +pub struct LocalExpressionContext<'temp, 'out> { /// A map from [`ast::Local`] handles to the Naga expressions we've built for them. /// /// This is always [`StatementContext::local_table`] for the /// enclosing statement; see that documentation for details. - local_table: &'temp FastHashMap, Typed>>, + local_table: &'temp FastHashMap, Declared>>>, function: &'out mut crate::Function, block: &'temp mut crate::Block, @@ -259,18 +286,18 @@ pub enum ExpressionContextType<'temp, 'out> { /// We are lowering to an arbitrary runtime expression, to be /// included in a function's body. /// - /// The given [`RuntimeExpressionContext`] holds information about local + /// The given [`LocalExpressionContext`] holds information about local /// variables, arguments, and other definitions available only to runtime /// expressions, not constant or override expressions. - Runtime(RuntimeExpressionContext<'temp, 'out>), + Runtime(LocalExpressionContext<'temp, 'out>), /// We are lowering to a constant expression, to be included in the module's /// constant expression arena. /// - /// Everything constant expressions are allowed to refer to is - /// available in the [`ExpressionContext`], so this variant - /// carries no further information. - Constant, + /// Everything global constant expressions are allowed to refer to is + /// available in the [`ExpressionContext`], but local constant expressions can + /// also refer to other + Constant(Option>), /// We are lowering to an override expression, to be included in the module's /// constant expression arena. @@ -352,7 +379,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { ast_expressions: self.ast_expressions, const_typifier: self.const_typifier, module: self.module, - expr_type: ExpressionContextType::Constant, + expr_type: ExpressionContextType::Constant(None), global_expression_kind_tracker: self.global_expression_kind_tracker, } } @@ -376,8 +403,19 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { rctx.local_expression_kind_tracker, rctx.emitter, rctx.block, + false, ), - ExpressionContextType::Constant => ConstantEvaluator::for_wgsl_module( + ExpressionContextType::Constant(Some(ref mut rctx)) => { + ConstantEvaluator::for_wgsl_function( + self.module, + &mut rctx.function.expressions, + rctx.local_expression_kind_tracker, + rctx.emitter, + rctx.block, + true, + ) + } + ExpressionContextType::Constant(None) => ConstantEvaluator::for_wgsl_module( self.module, self.global_expression_kind_tracker, false, @@ -397,7 +435,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { ) -> Result, Error<'source>> { let mut eval = self.as_const_evaluator(); eval.try_eval_and_append(expr, span) - .map_err(|e| Error::ConstantEvaluatorError(e, span)) + .map_err(|e| Error::ConstantEvaluatorError(e.into(), span)) } fn const_access(&self, handle: Handle) -> Option { @@ -412,15 +450,27 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { .eval_expr_to_u32_from(handle, &ctx.function.expressions) .ok() } - ExpressionContextType::Constant => self.module.to_ctx().eval_expr_to_u32(handle).ok(), + ExpressionContextType::Constant(Some(ref ctx)) => { + assert!(ctx.local_expression_kind_tracker.is_const(handle)); + self.module + .to_ctx() + .eval_expr_to_u32_from(handle, &ctx.function.expressions) + .ok() + } + ExpressionContextType::Constant(None) => { + self.module.to_ctx().eval_expr_to_u32(handle).ok() + } ExpressionContextType::Override => None, } } fn get_expression_span(&self, handle: Handle) -> Span { match self.expr_type { - ExpressionContextType::Runtime(ref ctx) => ctx.function.expressions.get_span(handle), - ExpressionContextType::Constant | ExpressionContextType::Override => { + ExpressionContextType::Runtime(ref ctx) + | ExpressionContextType::Constant(Some(ref ctx)) => { + ctx.function.expressions.get_span(handle) + } + ExpressionContextType::Constant(None) | ExpressionContextType::Override => { self.module.global_expressions.get_span(handle) } } @@ -428,20 +478,35 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { fn typifier(&self) -> &Typifier { match self.expr_type { - ExpressionContextType::Runtime(ref ctx) => ctx.typifier, - ExpressionContextType::Constant | ExpressionContextType::Override => { + ExpressionContextType::Runtime(ref ctx) + | ExpressionContextType::Constant(Some(ref ctx)) => ctx.typifier, + ExpressionContextType::Constant(None) | ExpressionContextType::Override => { self.const_typifier } } } + fn local( + &mut self, + local: &Handle, + span: Span, + ) -> Result>, Error<'source>> { + match self.expr_type { + ExpressionContextType::Runtime(ref ctx) => Ok(ctx.local_table[local].runtime()), + ExpressionContextType::Constant(Some(ref ctx)) => ctx.local_table[local] + .const_time() + .ok_or(Error::UnexpectedOperationInConstContext(span)), + _ => Err(Error::UnexpectedOperationInConstContext(span)), + } + } + fn runtime_expression_ctx( &mut self, span: Span, - ) -> Result<&mut RuntimeExpressionContext<'temp, 'out>, Error<'source>> { + ) -> Result<&mut LocalExpressionContext<'temp, 'out>, Error<'source>> { match self.expr_type { ExpressionContextType::Runtime(ref mut ctx) => Ok(ctx), - ExpressionContextType::Constant | ExpressionContextType::Override => { + ExpressionContextType::Constant(_) | ExpressionContextType::Override => { Err(Error::UnexpectedOperationInConstContext(span)) } } @@ -480,7 +545,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { } // This means a `gather` operation appeared in a constant expression. // This error refers to the `gather` itself, not its "component" argument. - ExpressionContextType::Constant | ExpressionContextType::Override => { + ExpressionContextType::Constant(_) | ExpressionContextType::Override => { Err(Error::UnexpectedOperationInConstContext(gather_span)) } } @@ -505,8 +570,9 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { // except that this lets the borrow checker see that it's okay // to also borrow self.module.types mutably below. let typifier = match self.expr_type { - ExpressionContextType::Runtime(ref ctx) => ctx.typifier, - ExpressionContextType::Constant | ExpressionContextType::Override => { + ExpressionContextType::Runtime(ref ctx) + | ExpressionContextType::Constant(Some(ref ctx)) => ctx.typifier, + ExpressionContextType::Constant(None) | ExpressionContextType::Override => { &*self.const_typifier } }; @@ -542,7 +608,8 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { let typifier; let expressions; match self.expr_type { - ExpressionContextType::Runtime(ref mut ctx) => { + ExpressionContextType::Runtime(ref mut ctx) + | ExpressionContextType::Constant(Some(ref mut ctx)) => { resolve_ctx = ResolveContext::with_locals( self.module, &ctx.function.local_variables, @@ -551,7 +618,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { typifier = &mut *ctx.typifier; expressions = &ctx.function.expressions; } - ExpressionContextType::Constant | ExpressionContextType::Override => { + ExpressionContextType::Constant(None) | ExpressionContextType::Override => { resolve_ctx = ResolveContext::with_locals(self.module, &empty_arena, &[]); typifier = self.const_typifier; expressions = &self.module.global_expressions; @@ -643,18 +710,20 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { span: Span, ) -> Result, Error<'source>> { match self.expr_type { - ExpressionContextType::Runtime(ref mut rctx) => { + ExpressionContextType::Runtime(ref mut rctx) + | ExpressionContextType::Constant(Some(ref mut rctx)) => { rctx.block .extend(rctx.emitter.finish(&rctx.function.expressions)); } - ExpressionContextType::Constant | ExpressionContextType::Override => {} + ExpressionContextType::Constant(None) | ExpressionContextType::Override => {} } let result = self.append_expression(expression, span); match self.expr_type { - ExpressionContextType::Runtime(ref mut rctx) => { + ExpressionContextType::Runtime(ref mut rctx) + | ExpressionContextType::Constant(Some(ref mut rctx)) => { rctx.emitter.start(&rctx.function.expressions); } - ExpressionContextType::Constant | ExpressionContextType::Override => {} + ExpressionContextType::Constant(None) | ExpressionContextType::Override => {} } result } @@ -718,6 +787,30 @@ impl<'source> ArgumentContext<'_, 'source> { } } +#[derive(Debug, Copy, Clone)] +enum Declared { + /// Value declared as const + Const(T), + + /// Value declared as non-const + Runtime(T), +} + +impl Declared { + fn runtime(self) -> T { + match self { + Declared::Const(t) | Declared::Runtime(t) => t, + } + } + + fn const_time(self) -> Option { + match self { + Declared::Const(t) => Some(t), + Declared::Runtime(_) => None, + } + } +} + /// WGSL type annotations on expressions, types, values, etc. /// /// Naga and WGSL types are very close, but Naga lacks WGSL's `ref` types, which @@ -814,7 +907,13 @@ impl Components { *comp = Self::letter_component(ch).ok_or(Error::BadAccessor(name_span))?; } - Ok(Components::Swizzle { size, pattern }) + if name.chars().all(|c| matches!(c, 'x' | 'y' | 'z' | 'w')) + || name.chars().all(|c| matches!(c, 'r' | 'g' | 'b' | 'a')) + { + Ok(Components::Swizzle { size, pattern }) + } else { + Err(Error::BadAccessor(name_span)) + } } } @@ -935,31 +1034,41 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ctx.globals.insert(f.name.name, lowered_decl); } ast::GlobalDeclKind::Var(ref v) => { - let ty = self.resolve_ast_type(v.ty, &mut ctx)?; - - let init; - if let Some(init_ast) = v.init { - let mut ectx = ctx.as_override(); - let lowered = self.expression_for_abstract(init_ast, &mut ectx)?; - let ty_res = crate::proc::TypeResolution::Handle(ty); - let converted = ectx - .try_automatic_conversions(lowered, &ty_res, v.name.span) - .map_err(|error| match error { - Error::AutoConversion { - dest_span: _, - dest_type, - source_span: _, - source_type, - } => Error::InitializationTypeMismatch { + let explicit_ty = + v.ty.map(|ast| self.resolve_ast_type(ast, &mut ctx)) + .transpose()?; + + let mut ectx = ctx.as_override(); + + let ty; + let initializer; + match (v.init, explicit_ty) { + (Some(init), Some(explicit_ty)) => { + let init = self.expression_for_abstract(init, &mut ectx)?; + let ty_res = crate::proc::TypeResolution::Handle(explicit_ty); + let init = ectx + .try_automatic_conversions(init, &ty_res, v.name.span) + .map_err(|error| match error { + Error::AutoConversion(e) => Error::InitializationTypeMismatch { name: v.name.span, - expected: dest_type, - got: source_type, + expected: e.dest_type, + got: e.source_type, }, other => other, })?; - init = Some(converted); - } else { - init = None; + ty = explicit_ty; + initializer = Some(init); + } + (Some(init), None) => { + let concretized = self.expression(init, &mut ectx)?; + ty = ectx.register_type(concretized)?; + initializer = Some(concretized); + } + (None, Some(explicit_ty)) => { + ty = explicit_ty; + initializer = None; + } + (None, None) => return Err(Error::DeclMissingTypeAndInit(v.name.span)), } let binding = if let Some(ref binding) = v.binding { @@ -977,7 +1086,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { space: v.space, binding, ty, - init, + init: initializer, }, span, ); @@ -997,15 +1106,10 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { init = ectx .try_automatic_conversions(init, &explicit_ty_res, c.name.span) .map_err(|error| match error { - Error::AutoConversion { - dest_span: _, - dest_type, - source_span: _, - source_type, - } => Error::InitializationTypeMismatch { + Error::AutoConversion(e) => Error::InitializationTypeMismatch { name: c.name.span, - expected: dest_type, - got: source_type, + expected: e.dest_type, + got: e.source_type, }, other => other, })?; @@ -1061,8 +1165,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let gctx = ctx.module.to_ctx(); return Err(Error::InitializationTypeMismatch { name: o.name.span, - expected: explicit_ty.to_wgsl(&gctx), - got: inferred_type.to_wgsl(&gctx), + expected: explicit_ty.to_wgsl(&gctx).into(), + got: inferred_type.to_wgsl(&gctx).into(), }); } } @@ -1100,6 +1204,20 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ctx.globals .insert(alias.name.name, LoweredGlobalDecl::Type(ty)); } + ast::GlobalDeclKind::ConstAssert(condition) => { + let condition = self.expression(condition, &mut ctx.as_const())?; + + let span = ctx.module.global_expressions.get_span(condition); + match ctx + .module + .to_ctx() + .eval_expr_to_bool_from(condition, &ctx.module.global_expressions) + { + Some(true) => Ok(()), + Some(false) => Err(Error::ConstAssertFailed(span)), + _ => Err(Error::NotBool(span)), + }?; + } } } @@ -1130,7 +1248,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let ty = self.resolve_ast_type(arg.ty, ctx)?; let expr = expressions .append(crate::Expression::FunctionArgument(i as u32), arg.name.span); - local_table.insert(arg.handle, Typed::Plain(expr)); + local_table.insert(arg.handle, Declared::Runtime(Typed::Plain(expr))); named_expressions.insert(expr, (arg.name.name.to_string(), arg.name.span)); local_expression_kind_tracker.insert(expr, crate::proc::ExpressionKind::Runtime); @@ -1271,14 +1389,15 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let gctx = &ctx.module.to_ctx(); return Err(Error::InitializationTypeMismatch { name: l.name.span, - expected: ty.to_wgsl(gctx), - got: init_ty.to_wgsl(gctx), + expected: ty.to_wgsl(gctx).into(), + got: init_ty.to_wgsl(gctx).into(), }); } } block.extend(emitter.finish(&ctx.function.expressions)); - ctx.local_table.insert(l.handle, Typed::Plain(value)); + ctx.local_table + .insert(l.handle, Declared::Runtime(Typed::Plain(value))); ctx.named_expressions .insert(value, (l.name.name.to_string(), l.name.span)); @@ -1302,15 +1421,10 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let init = ectx .try_automatic_conversions(init, &ty_res, v.name.span) .map_err(|error| match error { - Error::AutoConversion { - dest_span: _, - dest_type, - source_span: _, - source_type, - } => Error::InitializationTypeMismatch { + Error::AutoConversion(e) => Error::InitializationTypeMismatch { name: v.name.span, - expected: dest_type, - got: source_type, + expected: e.dest_type, + got: e.source_type, }, other => other, })?; @@ -1365,7 +1479,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { Span::UNDEFINED, )?; block.extend(emitter.finish(&ctx.function.expressions)); - ctx.local_table.insert(v.handle, Typed::Reference(handle)); + ctx.local_table + .insert(v.handle, Declared::Runtime(Typed::Reference(handle))); match initializer { Some(initializer) => crate::Statement::Store { @@ -1375,6 +1490,41 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { None => return Ok(()), } } + ast::LocalDecl::Const(ref c) => { + let mut emitter = Emitter::default(); + emitter.start(&ctx.function.expressions); + + let ectx = &mut ctx.as_const(block, &mut emitter); + + let mut init = self.expression_for_abstract(c.init, ectx)?; + + if let Some(explicit_ty) = c.ty { + let explicit_ty = + self.resolve_ast_type(explicit_ty, &mut ectx.as_global())?; + let explicit_ty_res = crate::proc::TypeResolution::Handle(explicit_ty); + init = ectx + .try_automatic_conversions(init, &explicit_ty_res, c.name.span) + .map_err(|error| match error { + Error::AutoConversion(error) => Error::InitializationTypeMismatch { + name: c.name.span, + expected: error.dest_type, + got: error.source_type, + }, + other => other, + })?; + } else { + init = ectx.concretize(init)?; + ectx.register_type(init)?; + } + + block.extend(emitter.finish(&ctx.function.expressions)); + ctx.local_table + .insert(c.handle, Declared::Const(Typed::Plain(init))); + ctx.named_expressions + .insert(init, (c.name.name.to_string(), c.name.span)); + + return Ok(()); + } }, ast::StatementKind::If { condition, @@ -1606,6 +1756,28 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { value, } } + ast::StatementKind::ConstAssert(condition) => { + let mut emitter = Emitter::default(); + emitter.start(&ctx.function.expressions); + + let condition = + self.expression(condition, &mut ctx.as_const(block, &mut emitter))?; + + let span = ctx.function.expressions.get_span(condition); + match ctx + .module + .to_ctx() + .eval_expr_to_bool_from(condition, &ctx.function.expressions) + { + Some(true) => Ok(()), + Some(false) => Err(Error::ConstAssertFailed(span)), + _ => Err(Error::NotBool(span)), + }?; + + block.extend(emitter.finish(&ctx.function.expressions)); + + return Ok(()); + } ast::StatementKind::Ignore(expr) => { let mut emitter = Emitter::default(); emitter.start(&ctx.function.expressions); @@ -1673,8 +1845,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { return Ok(Typed::Plain(handle)); } ast::Expression::Ident(ast::IdentExpr::Local(local)) => { - let rctx = ctx.runtime_expression_ctx(span)?; - return Ok(rctx.local_table[&local]); + return ctx.local(&local, span); } ast::Expression::Ident(ast::IdentExpr::Unresolved(name)) => { let global = ctx @@ -1854,9 +2025,9 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let ty = resolve!(ctx, expr); let gctx = &ctx.module.to_ctx(); return Err(Error::BadTypeCast { - from_type: ty.to_wgsl(gctx), + from_type: ty.to_wgsl(gctx).into(), span: ty_span, - to_type: to_resolved.to_wgsl(gctx), + to_type: to_resolved.to_wgsl(gctx).into(), }); } }; @@ -2845,16 +3016,34 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ) -> Result, Error<'source>> { let inner = match ctx.types[handle] { ast::Type::Scalar(scalar) => scalar.to_inner_scalar(), - ast::Type::Vector { size, scalar } => scalar.to_inner_vector(size), + ast::Type::Vector { size, ty, ty_span } => { + let ty = self.resolve_ast_type(ty, ctx)?; + let scalar = match ctx.module.types[ty].inner { + crate::TypeInner::Scalar(sc) => sc, + _ => return Err(Error::UnknownScalarType(ty_span)), + }; + crate::TypeInner::Vector { size, scalar } + } ast::Type::Matrix { rows, columns, - width, - } => crate::TypeInner::Matrix { - columns, - rows, - scalar: crate::Scalar::float(width), - }, + ty, + ty_span, + } => { + let ty = self.resolve_ast_type(ty, ctx)?; + let scalar = match ctx.module.types[ty].inner { + crate::TypeInner::Scalar(sc) => sc, + _ => return Err(Error::UnknownScalarType(ty_span)), + }; + match scalar.kind { + crate::ScalarKind::Float => crate::TypeInner::Matrix { + columns, + rows, + scalar, + }, + _ => return Err(Error::BadMatrixScalarKind(ty_span, scalar)), + } + } ast::Type::Atomic(scalar) => scalar.to_inner_atomic(), ast::Type::Pointer { base, space } => { let base = self.resolve_ast_type(base, ctx)?; diff --git a/naga/src/front/wgsl/parse/ast.rs b/naga/src/front/wgsl/parse/ast.rs index 7df5c8a1c9..c4a7984115 100644 --- a/naga/src/front/wgsl/parse/ast.rs +++ b/naga/src/front/wgsl/parse/ast.rs @@ -85,6 +85,7 @@ pub enum GlobalDeclKind<'a> { Override(Override<'a>), Struct(Struct<'a>), Type(TypeAlias<'a>), + ConstAssert(Handle>), } #[derive(Debug)] @@ -109,7 +110,7 @@ pub struct EntryPoint<'a> { } #[cfg(doc)] -use crate::front::wgsl::lower::{RuntimeExpressionContext, StatementContext}; +use crate::front::wgsl::lower::{LocalExpressionContext, StatementContext}; #[derive(Debug)] pub struct Function<'a> { @@ -142,7 +143,7 @@ pub struct GlobalVariable<'a> { pub name: Ident<'a>, pub space: crate::AddressSpace, pub binding: Option>, - pub ty: Handle>, + pub ty: Option>>, pub init: Option>>, } @@ -198,12 +199,14 @@ pub enum Type<'a> { Scalar(Scalar), Vector { size: crate::VectorSize, - scalar: Scalar, + ty: Handle>, + ty_span: Span, }, Matrix { columns: crate::VectorSize, rows: crate::VectorSize, - width: crate::Bytes, + ty: Handle>, + ty_span: Span, }, Atomic(Scalar), Pointer { @@ -282,6 +285,7 @@ pub enum StatementKind<'a> { Increment(Handle>), Decrement(Handle>), Ignore(Handle>), + ConstAssert(Handle>), } #[derive(Debug)] @@ -330,7 +334,8 @@ pub enum ConstructorType<'a> { /// `vec3(1.0)`. Vector { size: crate::VectorSize, - scalar: Scalar, + ty: Handle>, + ty_span: Span, }, /// A matrix construction whose component type is inferred from the @@ -345,7 +350,8 @@ pub enum ConstructorType<'a> { Matrix { columns: crate::VectorSize, rows: crate::VectorSize, - width: crate::Bytes, + ty: Handle>, + ty_span: Span, }, /// An array whose component type and size are inferred from the arguments: @@ -460,14 +466,23 @@ pub struct Let<'a> { pub handle: Handle, } +#[derive(Debug)] +pub struct LocalConst<'a> { + pub name: Ident<'a>, + pub ty: Option>>, + pub init: Handle>, + pub handle: Handle, +} + #[derive(Debug)] pub enum LocalDecl<'a> { Var(LocalVariable<'a>), Let(Let<'a>), + Const(LocalConst<'a>), } #[derive(Debug)] /// A placeholder for a local variable declaration. /// -/// See [`Function::locals`] for more information. +/// See [`super::ExpressionContext::locals`] for more information. pub struct Local; diff --git a/naga/src/front/wgsl/parse/conv.rs b/naga/src/front/wgsl/parse/conv.rs index 4718b85e5e..3ba71b07cc 100644 --- a/naga/src/front/wgsl/parse/conv.rs +++ b/naga/src/front/wgsl/parse/conv.rs @@ -58,6 +58,8 @@ pub fn map_sampling(word: &str, span: Span) -> Result "center" => Ok(crate::Sampling::Center), "centroid" => Ok(crate::Sampling::Centroid), "sample" => Ok(crate::Sampling::Sample), + "first" => Ok(crate::Sampling::First), + "either" => Ok(crate::Sampling::Either), _ => Err(Error::UnknownAttribute(span)), } } @@ -92,7 +94,7 @@ pub fn map_storage_format(word: &str, span: Span) -> Result Sf::Rgba8Sint, "rgb10a2uint" => Sf::Rgb10a2Uint, "rgb10a2unorm" => Sf::Rgb10a2Unorm, - "rg11b10float" => Sf::Rg11b10UFloat, + "rg11b10float" => Sf::Rg11b10Ufloat, "rg32uint" => Sf::Rg32Uint, "rg32sint" => Sf::Rg32Sint, "rg32float" => Sf::Rg32Float, diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index c9114d685d..0157aa3a78 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -31,20 +31,20 @@ struct ExpressionContext<'input, 'temp, 'out> { /// A map from identifiers in scope to the locals/arguments they represent. /// - /// The handles refer to the [`Function::locals`] area; see that field's + /// The handles refer to the [`locals`] arena; see that field's /// documentation for details. /// - /// [`Function::locals`]: ast::Function::locals + /// [`locals`]: ExpressionContext::locals local_table: &'temp mut SymbolTable<&'input str, Handle>, /// Local variable and function argument arena for the function we're building. /// - /// Note that the `Local` here is actually a zero-sized type. The AST keeps - /// all the detailed information about locals - names, types, etc. - in - /// [`LocalDecl`] statements. For arguments, that information is kept in - /// [`arguments`]. This `Arena`'s only role is to assign a unique `Handle` - /// to each of them, and track their definitions' spans for use in - /// diagnostics. + /// Note that the [`ast::Local`] here is actually a zero-sized type. This + /// `Arena`'s only role is to assign a unique `Handle` to each local + /// identifier, and track its definition's span for use in diagnostics. All + /// the detailed information about locals - names, types, etc. - is kept in + /// the [`LocalDecl`] statements we parsed from their declarations. For + /// arguments, that information is kept in [`arguments`]. /// /// In the AST, when an [`Ident`] expression refers to a local variable or /// argument, its [`IdentExpr`] holds the referent's `Handle` in this @@ -53,14 +53,15 @@ struct ExpressionContext<'input, 'temp, 'out> { /// During lowering, [`LocalDecl`] statements add entries to a per-function /// table that maps `Handle` values to their Naga representations, /// accessed via [`StatementContext::local_table`] and - /// [`RuntimeExpressionContext::local_table`]. This table is then consulted when + /// [`LocalExpressionContext::local_table`]. This table is then consulted when /// lowering subsequent [`Ident`] expressions. /// - /// [`LocalDecl`]: StatementKind::LocalDecl - /// [`arguments`]: Function::arguments - /// [`Ident`]: Expression::Ident - /// [`StatementContext::local_table`]: StatementContext::local_table - /// [`RuntimeExpressionContext::local_table`]: RuntimeExpressionContext::local_table + /// [`LocalDecl`]: ast::StatementKind::LocalDecl + /// [`arguments`]: ast::Function::arguments + /// [`Ident`]: ast::Expression::Ident + /// [`IdentExpr`]: ast::IdentExpr + /// [`StatementContext::local_table`]: super::lower::StatementContext::local_table + /// [`LocalExpressionContext::local_table`]: super::lower::LocalExpressionContext::local_table locals: &'out mut Arena, /// Identifiers used by the current global declaration that have no local definition. @@ -111,6 +112,11 @@ impl<'a> ExpressionContext<'a, '_, '_> { Ok(handle) } } + + fn new_scalar(&mut self, scalar: Scalar) -> Handle> { + self.types + .append(ast::Type::Scalar(scalar), Span::UNDEFINED) + } } /// Which grammar rule we are in the midst of parsing. @@ -310,25 +316,22 @@ impl Parser { "vec2i" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Bi, - scalar: Scalar { - kind: crate::ScalarKind::Sint, - width: 4, - }, + ty: ctx.new_scalar(Scalar::I32), + ty_span: Span::UNDEFINED, })) } "vec2u" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Bi, - scalar: Scalar { - kind: crate::ScalarKind::Uint, - width: 4, - }, + ty: ctx.new_scalar(Scalar::U32), + ty_span: Span::UNDEFINED, })) } "vec2f" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Bi, - scalar: Scalar::F32, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "vec3" => ast::ConstructorType::PartialVector { @@ -337,19 +340,22 @@ impl Parser { "vec3i" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Tri, - scalar: Scalar::I32, + ty: ctx.new_scalar(Scalar::I32), + ty_span: Span::UNDEFINED, })) } "vec3u" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Tri, - scalar: Scalar::U32, + ty: ctx.new_scalar(Scalar::U32), + ty_span: Span::UNDEFINED, })) } "vec3f" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Tri, - scalar: Scalar::F32, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "vec4" => ast::ConstructorType::PartialVector { @@ -358,19 +364,22 @@ impl Parser { "vec4i" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Quad, - scalar: Scalar::I32, + ty: ctx.new_scalar(Scalar::I32), + ty_span: Span::UNDEFINED, })) } "vec4u" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Quad, - scalar: Scalar::U32, + ty: ctx.new_scalar(Scalar::U32), + ty_span: Span::UNDEFINED, })) } "vec4f" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Quad, - scalar: Scalar::F32, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat2x2" => ast::ConstructorType::PartialMatrix { @@ -381,7 +390,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Bi, rows: crate::VectorSize::Bi, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat2x3" => ast::ConstructorType::PartialMatrix { @@ -392,7 +402,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Bi, rows: crate::VectorSize::Tri, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat2x4" => ast::ConstructorType::PartialMatrix { @@ -403,7 +414,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Bi, rows: crate::VectorSize::Quad, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat3x2" => ast::ConstructorType::PartialMatrix { @@ -414,7 +426,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Tri, rows: crate::VectorSize::Bi, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat3x3" => ast::ConstructorType::PartialMatrix { @@ -425,7 +438,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Tri, rows: crate::VectorSize::Tri, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat3x4" => ast::ConstructorType::PartialMatrix { @@ -436,7 +450,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Tri, rows: crate::VectorSize::Quad, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat4x2" => ast::ConstructorType::PartialMatrix { @@ -447,7 +462,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Quad, rows: crate::VectorSize::Bi, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat4x3" => ast::ConstructorType::PartialMatrix { @@ -458,7 +474,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Quad, rows: crate::VectorSize::Tri, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "mat4x4" => ast::ConstructorType::PartialMatrix { @@ -469,7 +486,8 @@ impl Parser { return Ok(Some(ast::ConstructorType::Matrix { columns: crate::VectorSize::Quad, rows: crate::VectorSize::Quad, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, })) } "array" => ast::ConstructorType::PartialArray, @@ -502,19 +520,17 @@ impl Parser { // parse component type if present match (lexer.peek().0, partial) { (Token::Paren('<'), ast::ConstructorType::PartialVector { size }) => { - let scalar = lexer.next_scalar_generic()?; - Ok(Some(ast::ConstructorType::Vector { size, scalar })) + let (ty, ty_span) = self.singular_generic(lexer, ctx)?; + Ok(Some(ast::ConstructorType::Vector { size, ty, ty_span })) } (Token::Paren('<'), ast::ConstructorType::PartialMatrix { columns, rows }) => { - let (scalar, span) = lexer.next_scalar_generic_with_span()?; - match scalar.kind { - crate::ScalarKind::Float => Ok(Some(ast::ConstructorType::Matrix { - columns, - rows, - width: scalar.width, - })), - _ => Err(Error::BadMatrixScalarKind(span, scalar)), - } + let (ty, ty_span) = self.singular_generic(lexer, ctx)?; + Ok(Some(ast::ConstructorType::Matrix { + columns, + rows, + ty, + ty_span, + })) } (Token::Paren('<'), ast::ConstructorType::PartialArray) => { lexer.expect_generic_paren('<')?; @@ -570,11 +586,7 @@ impl Parser { let expr = match name { // bitcast looks like a function call, but it's an operator and must be handled differently. "bitcast" => { - lexer.expect_generic_paren('<')?; - let start = lexer.start_byte_offset(); - let to = self.type_decl(lexer, ctx)?; - let span = lexer.span_from(start); - lexer.expect_generic_paren('>')?; + let (to, span) = self.singular_generic(lexer, ctx)?; lexer.open_arguments()?; let expr = self.general_expression(lexer, ctx)?; @@ -980,8 +992,12 @@ impl Parser { lexer.expect(Token::Paren('>'))?; } let name = lexer.next_ident()?; - lexer.expect(Token::Separator(':'))?; - let ty = self.type_decl(lexer, ctx)?; + + let ty = if lexer.skip(Token::Separator(':')) { + Some(self.type_decl(lexer, ctx)?) + } else { + None + }; let init = if lexer.skip(Token::Operation('=')) { let handle = self.general_expression(lexer, ctx)?; @@ -1058,21 +1074,34 @@ impl Parser { Ok(members) } - fn matrix_scalar_type<'a>( + /// Parses ``, returning T and span of T + fn singular_generic<'a>( + &mut self, + lexer: &mut Lexer<'a>, + ctx: &mut ExpressionContext<'a, '_, '_>, + ) -> Result<(Handle>, Span), Error<'a>> { + lexer.expect_generic_paren('<')?; + let start = lexer.start_byte_offset(); + let ty = self.type_decl(lexer, ctx)?; + let span = lexer.span_from(start); + lexer.expect_generic_paren('>')?; + Ok((ty, span)) + } + + fn matrix_with_type<'a>( &mut self, lexer: &mut Lexer<'a>, + ctx: &mut ExpressionContext<'a, '_, '_>, columns: crate::VectorSize, rows: crate::VectorSize, ) -> Result, Error<'a>> { - let (scalar, span) = lexer.next_scalar_generic_with_span()?; - match scalar.kind { - crate::ScalarKind::Float => Ok(ast::Type::Matrix { - columns, - rows, - width: scalar.width, - }), - _ => Err(Error::BadMatrixScalarKind(span, scalar)), - } + let (ty, ty_span) = self.singular_generic(lexer, ctx)?; + Ok(ast::Type::Matrix { + columns, + rows, + ty, + ty_span, + }) } fn type_decl_impl<'a>( @@ -1087,151 +1116,154 @@ impl Parser { Ok(Some(match word { "vec2" => { - let scalar = lexer.next_scalar_generic()?; + let (ty, ty_span) = self.singular_generic(lexer, ctx)?; ast::Type::Vector { size: crate::VectorSize::Bi, - scalar, + ty, + ty_span, } } "vec2i" => ast::Type::Vector { size: crate::VectorSize::Bi, - scalar: Scalar { - kind: crate::ScalarKind::Sint, - width: 4, - }, + ty: ctx.new_scalar(Scalar::I32), + ty_span: Span::UNDEFINED, }, "vec2u" => ast::Type::Vector { size: crate::VectorSize::Bi, - scalar: Scalar { - kind: crate::ScalarKind::Uint, - width: 4, - }, + ty: ctx.new_scalar(Scalar::U32), + ty_span: Span::UNDEFINED, }, "vec2f" => ast::Type::Vector { size: crate::VectorSize::Bi, - scalar: Scalar::F32, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "vec3" => { - let scalar = lexer.next_scalar_generic()?; + let (ty, ty_span) = self.singular_generic(lexer, ctx)?; ast::Type::Vector { size: crate::VectorSize::Tri, - scalar, + ty, + ty_span, } } "vec3i" => ast::Type::Vector { size: crate::VectorSize::Tri, - scalar: Scalar { - kind: crate::ScalarKind::Sint, - width: 4, - }, + ty: ctx.new_scalar(Scalar::I32), + ty_span: Span::UNDEFINED, }, "vec3u" => ast::Type::Vector { size: crate::VectorSize::Tri, - scalar: Scalar { - kind: crate::ScalarKind::Uint, - width: 4, - }, + ty: ctx.new_scalar(Scalar::U32), + ty_span: Span::UNDEFINED, }, "vec3f" => ast::Type::Vector { size: crate::VectorSize::Tri, - scalar: Scalar::F32, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "vec4" => { - let scalar = lexer.next_scalar_generic()?; + let (ty, ty_span) = self.singular_generic(lexer, ctx)?; ast::Type::Vector { size: crate::VectorSize::Quad, - scalar, + ty, + ty_span, } } "vec4i" => ast::Type::Vector { size: crate::VectorSize::Quad, - scalar: Scalar { - kind: crate::ScalarKind::Sint, - width: 4, - }, + ty: ctx.new_scalar(Scalar::I32), + ty_span: Span::UNDEFINED, }, "vec4u" => ast::Type::Vector { size: crate::VectorSize::Quad, - scalar: Scalar { - kind: crate::ScalarKind::Uint, - width: 4, - }, + ty: ctx.new_scalar(Scalar::U32), + ty_span: Span::UNDEFINED, }, "vec4f" => ast::Type::Vector { size: crate::VectorSize::Quad, - scalar: Scalar::F32, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat2x2" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Bi)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Bi)? } "mat2x2f" => ast::Type::Matrix { columns: crate::VectorSize::Bi, rows: crate::VectorSize::Bi, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat2x3" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Tri)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Tri)? } "mat2x3f" => ast::Type::Matrix { columns: crate::VectorSize::Bi, rows: crate::VectorSize::Tri, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat2x4" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Quad)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Quad)? } "mat2x4f" => ast::Type::Matrix { columns: crate::VectorSize::Bi, rows: crate::VectorSize::Quad, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat3x2" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Tri, crate::VectorSize::Bi)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Bi)? } "mat3x2f" => ast::Type::Matrix { columns: crate::VectorSize::Tri, rows: crate::VectorSize::Bi, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat3x3" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Tri, crate::VectorSize::Tri)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Tri)? } "mat3x3f" => ast::Type::Matrix { columns: crate::VectorSize::Tri, rows: crate::VectorSize::Tri, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat3x4" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Tri, crate::VectorSize::Quad)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Quad)? } "mat3x4f" => ast::Type::Matrix { columns: crate::VectorSize::Tri, rows: crate::VectorSize::Quad, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat4x2" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Quad, crate::VectorSize::Bi)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Bi)? } "mat4x2f" => ast::Type::Matrix { columns: crate::VectorSize::Quad, rows: crate::VectorSize::Bi, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat4x3" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Quad, crate::VectorSize::Tri)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Tri)? } "mat4x3f" => ast::Type::Matrix { columns: crate::VectorSize::Quad, rows: crate::VectorSize::Tri, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "mat4x4" => { - self.matrix_scalar_type(lexer, crate::VectorSize::Quad, crate::VectorSize::Quad)? + self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Quad)? } "mat4x4f" => ast::Type::Matrix { columns: crate::VectorSize::Quad, rows: crate::VectorSize::Quad, - width: 4, + ty: ctx.new_scalar(Scalar::F32), + ty_span: Span::UNDEFINED, }, "atomic" => { let scalar = lexer.next_scalar_generic()?; @@ -1688,6 +1720,28 @@ impl Parser { handle, })) } + "const" => { + let _ = lexer.next(); + let name = lexer.next_ident()?; + + let given_ty = if lexer.skip(Token::Separator(':')) { + let ty = self.type_decl(lexer, ctx)?; + Some(ty) + } else { + None + }; + lexer.expect(Token::Operation('='))?; + let expr_id = self.general_expression(lexer, ctx)?; + lexer.expect(Token::Separator(';'))?; + + let handle = ctx.declare_local(name)?; + ast::StatementKind::LocalDecl(ast::LocalDecl::Const(ast::LocalConst { + name, + ty: given_ty, + init: expr_id, + handle, + })) + } "var" => { let _ = lexer.next(); @@ -1963,6 +2017,20 @@ impl Parser { lexer.expect(Token::Separator(';'))?; ast::StatementKind::Kill } + // https://www.w3.org/TR/WGSL/#const-assert-statement + "const_assert" => { + let _ = lexer.next(); + // parentheses are optional + let paren = lexer.skip(Token::Paren('(')); + + let condition = self.general_expression(lexer, ctx)?; + + if paren { + lexer.expect(Token::Paren(')'))?; + } + lexer.expect(Token::Separator(';'))?; + ast::StatementKind::ConstAssert(condition) + } // assignment or a function call _ => { self.function_call_or_assignment_statement(lexer, ctx, block)?; @@ -2366,6 +2434,18 @@ impl Parser { ..function })) } + (Token::Word("const_assert"), _) => { + // parentheses are optional + let paren = lexer.skip(Token::Paren('(')); + + let condition = self.general_expression(lexer, &mut ctx)?; + + if paren { + lexer.expect(Token::Paren(')'))?; + } + lexer.expect(Token::Separator(';'))?; + Some(ast::GlobalDeclKind::ConstAssert(condition)) + } (Token::End, _) => return Ok(()), other => return Err(Error::Unexpected(other.1, ExpectedToken::GlobalItem)), }; diff --git a/naga/src/front/wgsl/to_wgsl.rs b/naga/src/front/wgsl/to_wgsl.rs index ec3af8edd4..0884e0003b 100644 --- a/naga/src/front/wgsl/to_wgsl.rs +++ b/naga/src/front/wgsl/to_wgsl.rs @@ -175,7 +175,7 @@ impl crate::StorageFormat { Sf::Bgra8Unorm => "bgra8unorm", Sf::Rgb10a2Uint => "rgb10a2uint", Sf::Rgb10a2Unorm => "rgb10a2unorm", - Sf::Rg11b10UFloat => "rg11b10float", + Sf::Rg11b10Ufloat => "rg11b10float", Sf::Rg32Uint => "rg32uint", Sf::Rg32Sint => "rg32sint", Sf::Rg32Float => "rg32float", diff --git a/naga/src/lib.rs b/naga/src/lib.rs index 60e5a1f47b..85fd7a4508 100644 --- a/naga/src/lib.rs +++ b/naga/src/lib.rs @@ -530,6 +530,13 @@ pub enum Sampling { /// Interpolate the value at each sample location. In multisampling, invoke /// the fragment shader once per sample. Sample, + + /// Use the value provided by the first vertex of the current primitive. + First, + + /// Use the value provided by the first or last vertex of the current primitive. The exact + /// choice is implementation-dependent. + Either, } /// Member of a user-defined structure. @@ -615,7 +622,7 @@ pub enum StorageFormat { // Packed 32-bit formats Rgb10a2Uint, Rgb10a2Unorm, - Rg11b10UFloat, + Rg11b10Ufloat, // 64-bit formats Rg32Uint, diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index deaa9c93c7..1b7f5cf910 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -317,7 +317,7 @@ pub struct ConstantEvaluator<'a> { #[derive(Debug)] enum WgslRestrictions<'a> { /// - const-expressions will be evaluated and inserted in the arena - Const, + Const(Option>), /// - const-expressions will be evaluated and inserted in the arena /// - override-expressions will be inserted in the arena Override, @@ -347,6 +347,8 @@ struct FunctionLocalData<'a> { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum ExpressionKind { + /// If const is also implemented as const + ImplConst, Const, Override, Runtime, @@ -372,14 +374,23 @@ impl ExpressionKindTracker { pub fn insert(&mut self, value: Handle, expr_type: ExpressionKind) { self.inner.insert(value, expr_type); } + pub fn is_const(&self, h: Handle) -> bool { - matches!(self.type_of(h), ExpressionKind::Const) + matches!( + self.type_of(h), + ExpressionKind::Const | ExpressionKind::ImplConst + ) + } + + /// Returns `true` if naga can also evaluate expression as const + pub fn is_impl_const(&self, h: Handle) -> bool { + matches!(self.type_of(h), ExpressionKind::ImplConst) } pub fn is_const_or_override(&self, h: Handle) -> bool { matches!( self.type_of(h), - ExpressionKind::Const | ExpressionKind::Override + ExpressionKind::Const | ExpressionKind::Override | ExpressionKind::ImplConst ) } @@ -400,13 +411,14 @@ impl ExpressionKindTracker { } fn type_of_with_expr(&self, expr: &Expression) -> ExpressionKind { + use crate::MathFunction as Mf; match *expr { Expression::Literal(_) | Expression::ZeroValue(_) | Expression::Constant(_) => { - ExpressionKind::Const + ExpressionKind::ImplConst } Expression::Override(_) => ExpressionKind::Override, Expression::Compose { ref components, .. } => { - let mut expr_type = ExpressionKind::Const; + let mut expr_type = ExpressionKind::ImplConst; for component in components { expr_type = expr_type.max(self.type_of(*component)) } @@ -417,13 +429,16 @@ impl ExpressionKindTracker { Expression::Access { base, index } => self.type_of(base).max(self.type_of(index)), Expression::Swizzle { vector, .. } => self.type_of(vector), Expression::Unary { expr, .. } => self.type_of(expr), - Expression::Binary { left, right, .. } => self.type_of(left).max(self.type_of(right)), + Expression::Binary { left, right, .. } => self + .type_of(left) + .max(self.type_of(right)) + .max(ExpressionKind::Const), Expression::Math { + fun, arg, arg1, arg2, arg3, - .. } => self .type_of(arg) .max( @@ -437,8 +452,34 @@ impl ExpressionKindTracker { .max( arg3.map(|arg| self.type_of(arg)) .unwrap_or(ExpressionKind::Const), + ) + .max( + if matches!( + fun, + Mf::Dot + | Mf::Outer + | Mf::Cross + | Mf::Distance + | Mf::Length + | Mf::Normalize + | Mf::FaceForward + | Mf::Reflect + | Mf::Refract + | Mf::Ldexp + | Mf::Modf + | Mf::Mix + | Mf::Frexp + ) { + ExpressionKind::Const + } else { + ExpressionKind::ImplConst + }, ), - Expression::As { expr, .. } => self.type_of(expr), + Expression::As { convert, expr, .. } => self.type_of(expr).max(if convert.is_some() { + ExpressionKind::ImplConst + } else { + ExpressionKind::Const + }), Expression::Select { condition, accept, @@ -446,7 +487,8 @@ impl ExpressionKindTracker { } => self .type_of(condition) .max(self.type_of(accept)) - .max(self.type_of(reject)), + .max(self.type_of(reject)) + .max(ExpressionKind::Const), Expression::Relational { argument, .. } => self.type_of(argument), Expression::ArrayLength(expr) => self.type_of(expr), _ => ExpressionKind::Runtime, @@ -556,7 +598,7 @@ impl<'a> ConstantEvaluator<'a> { Behavior::Wgsl(if in_override_ctx { WgslRestrictions::Override } else { - WgslRestrictions::Const + WgslRestrictions::Const(None) }), module, global_expression_kind_tracker, @@ -603,13 +645,19 @@ impl<'a> ConstantEvaluator<'a> { local_expression_kind_tracker: &'a mut ExpressionKindTracker, emitter: &'a mut super::Emitter, block: &'a mut crate::Block, + is_const: bool, ) -> Self { + let local_data = FunctionLocalData { + global_expressions: &module.global_expressions, + emitter, + block, + }; Self { - behavior: Behavior::Wgsl(WgslRestrictions::Runtime(FunctionLocalData { - global_expressions: &module.global_expressions, - emitter, - block, - })), + behavior: Behavior::Wgsl(if is_const { + WgslRestrictions::Const(Some(local_data)) + } else { + WgslRestrictions::Runtime(local_data) + }), types: &mut module.types, constants: &module.constants, overrides: &module.overrides, @@ -718,6 +766,7 @@ impl<'a> ConstantEvaluator<'a> { span: Span, ) -> Result, ConstantEvaluatorError> { match self.expression_kind_tracker.type_of_with_expr(&expr) { + ExpressionKind::ImplConst => self.try_eval_and_append_impl(&expr, span), ExpressionKind::Const => { let eval_result = self.try_eval_and_append_impl(&expr, span); // We should be able to evaluate `Const` expressions at this @@ -740,7 +789,7 @@ impl<'a> ConstantEvaluator<'a> { Behavior::Wgsl(WgslRestrictions::Override | WgslRestrictions::Runtime(_)) => { Ok(self.append_expr(expr, span, ExpressionKind::Override)) } - Behavior::Wgsl(WgslRestrictions::Const) => { + Behavior::Wgsl(WgslRestrictions::Const(_)) => { Err(ConstantEvaluatorError::OverrideExpr) } Behavior::Glsl(_) => { @@ -761,14 +810,17 @@ impl<'a> ConstantEvaluator<'a> { const fn is_global_arena(&self) -> bool { matches!( self.behavior, - Behavior::Wgsl(WgslRestrictions::Const | WgslRestrictions::Override) + Behavior::Wgsl(WgslRestrictions::Const(None) | WgslRestrictions::Override) | Behavior::Glsl(GlslRestrictions::Const) ) } const fn function_local_data(&self) -> Option<&FunctionLocalData<'a>> { match self.behavior { - Behavior::Wgsl(WgslRestrictions::Runtime(ref function_local_data)) + Behavior::Wgsl( + WgslRestrictions::Runtime(ref function_local_data) + | WgslRestrictions::Const(Some(ref function_local_data)), + ) | Behavior::Glsl(GlslRestrictions::Runtime(ref function_local_data)) => { Some(function_local_data) } @@ -1779,9 +1831,13 @@ impl<'a> ConstantEvaluator<'a> { _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs), }), (Literal::I32(a), Literal::U32(b)) => Literal::I32(match op { - BinaryOperator::ShiftLeft => a - .checked_shl(b) - .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?, + BinaryOperator::ShiftLeft => { + if (if a.is_negative() { !a } else { a }).leading_zeros() <= b { + return Err(ConstantEvaluatorError::Overflow("<<".to_string())); + } + a.checked_shl(b) + .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)? + } BinaryOperator::ShiftRight => a .checked_shr(b) .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?, @@ -1807,8 +1863,11 @@ impl<'a> ConstantEvaluator<'a> { BinaryOperator::ExclusiveOr => a ^ b, BinaryOperator::InclusiveOr => a | b, BinaryOperator::ShiftLeft => a - .checked_shl(b) - .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?, + .checked_mul( + 1u32.checked_shl(b) + .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?, + ) + .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?, BinaryOperator::ShiftRight => a .checked_shr(b) .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?, @@ -2057,7 +2116,10 @@ impl<'a> ConstantEvaluator<'a> { expr_type: ExpressionKind, ) -> Handle { let h = match self.behavior { - Behavior::Wgsl(WgslRestrictions::Runtime(ref mut function_local_data)) + Behavior::Wgsl( + WgslRestrictions::Runtime(ref mut function_local_data) + | WgslRestrictions::Const(Some(ref mut function_local_data)), + ) | Behavior::Glsl(GlslRestrictions::Runtime(ref mut function_local_data)) => { let is_running = function_local_data.emitter.is_running(); let needs_pre_emit = expr.needs_pre_emit(); @@ -2480,7 +2542,7 @@ mod tests { let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl(WgslRestrictions::Const), + behavior: Behavior::Wgsl(WgslRestrictions::Const(None)), types: &mut types, constants: &constants, overrides: &overrides, @@ -2566,7 +2628,7 @@ mod tests { let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl(WgslRestrictions::Const), + behavior: Behavior::Wgsl(WgslRestrictions::Const(None)), types: &mut types, constants: &constants, overrides: &overrides, @@ -2684,7 +2746,7 @@ mod tests { let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl(WgslRestrictions::Const), + behavior: Behavior::Wgsl(WgslRestrictions::Const(None)), types: &mut types, constants: &constants, overrides: &overrides, @@ -2777,7 +2839,7 @@ mod tests { let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl(WgslRestrictions::Const), + behavior: Behavior::Wgsl(WgslRestrictions::Const(None)), types: &mut types, constants: &constants, overrides: &overrides, @@ -2859,7 +2921,7 @@ mod tests { let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions); let mut solver = ConstantEvaluator { - behavior: Behavior::Wgsl(WgslRestrictions::Const), + behavior: Behavior::Wgsl(WgslRestrictions::Const(None)), types: &mut types, constants: &constants, overrides: &overrides, diff --git a/naga/src/proc/mod.rs b/naga/src/proc/mod.rs index 642c016615..a5b3ea4e38 100644 --- a/naga/src/proc/mod.rs +++ b/naga/src/proc/mod.rs @@ -48,7 +48,7 @@ impl From for super::ScalarKind { Sf::Bgra8Unorm => Sk::Float, Sf::Rgb10a2Uint => Sk::Uint, Sf::Rgb10a2Unorm => Sk::Float, - Sf::Rg11b10UFloat => Sk::Float, + Sf::Rg11b10Ufloat => Sk::Float, Sf::Rg32Uint => Sk::Uint, Sf::Rg32Sint => Sk::Sint, Sf::Rg32Float => Sk::Float, @@ -674,6 +674,19 @@ impl GlobalCtx<'_> { } } + /// Try to evaluate the expression in the `arena` using its `handle` and return it as a `bool`. + #[allow(dead_code)] + pub(super) fn eval_expr_to_bool_from( + &self, + handle: crate::Handle, + arena: &crate::Arena, + ) -> Option { + match self.eval_expr_to_literal_from(handle, arena) { + Some(crate::Literal::Bool(value)) => Some(value), + _ => None, + } + } + #[allow(dead_code)] pub(crate) fn eval_expr_to_literal( &self, diff --git a/naga/src/valid/expression.rs b/naga/src/valid/expression.rs index 1d1420aef6..0b0d115c57 100644 --- a/naga/src/valid/expression.rs +++ b/naga/src/valid/expression.rs @@ -1161,7 +1161,7 @@ impl super::Validator { )); } } - Mf::Outer | Mf::Cross | Mf::Reflect => { + Mf::Outer | Mf::Reflect => { let arg1_ty = match (arg1_ty, arg2_ty, arg3_ty) { (Some(ty1), None, None) => ty1, _ => return Err(ExpressionError::WrongArgumentCount(fun)), @@ -1184,6 +1184,29 @@ impl super::Validator { )); } } + Mf::Cross => { + let arg1_ty = match (arg1_ty, arg2_ty, arg3_ty) { + (Some(ty1), None, None) => ty1, + _ => return Err(ExpressionError::WrongArgumentCount(fun)), + }; + match *arg_ty { + Ti::Vector { + scalar: + Sc { + kind: Sk::Float, .. + }, + size: crate::VectorSize::Tri, + } => {} + _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), + } + if arg1_ty != arg_ty { + return Err(ExpressionError::InvalidArgumentType( + fun, + 1, + arg1.unwrap(), + )); + } + } Mf::Refract => { let (arg1_ty, arg2_ty) = match (arg1_ty, arg2_ty, arg3_ty) { (Some(ty1), Some(ty2), None) => (ty1, ty2), diff --git a/naga/src/valid/interface.rs b/naga/src/valid/interface.rs index 7fce9c8fd9..150a1f9df5 100644 --- a/naga/src/valid/interface.rs +++ b/naga/src/valid/interface.rs @@ -50,6 +50,11 @@ pub enum VaryingError { NotIOShareableType(Handle), #[error("Interpolation is not valid")] InvalidInterpolation, + #[error("Cannot combine {interpolation:?} interpolation with the {sampling:?} sample type")] + InvalidInterpolationSamplingCombination { + interpolation: crate::Interpolation, + sampling: crate::Sampling, + }, #[error("Interpolation must be specified on vertex shader outputs and fragment shader inputs")] MissingInterpolation, #[error("Built-in {0:?} is not available at this stage")] @@ -339,6 +344,31 @@ impl VaryingContext<'_> { } } + if let Some(interpolation) = interpolation { + let invalid_sampling = match (interpolation, sampling) { + (_, None) + | ( + crate::Interpolation::Perspective | crate::Interpolation::Linear, + Some( + crate::Sampling::Center + | crate::Sampling::Centroid + | crate::Sampling::Sample, + ), + ) + | ( + crate::Interpolation::Flat, + Some(crate::Sampling::First | crate::Sampling::Either), + ) => None, + (_, Some(invalid_sampling)) => Some(invalid_sampling), + }; + if let Some(sampling) = invalid_sampling { + return Err(VaryingError::InvalidInterpolationSamplingCombination { + interpolation, + sampling, + }); + } + } + let needs_interpolation = match self.stage { crate::ShaderStage::Vertex => self.output, crate::ShaderStage::Fragment => !self.output, diff --git a/naga/tests/in/abstract-types-var.wgsl b/naga/tests/in/abstract-types-var.wgsl index a733888530..c573f73d57 100644 --- a/naga/tests/in/abstract-types-var.wgsl +++ b/naga/tests/in/abstract-types-var.wgsl @@ -43,6 +43,20 @@ var xafpaiaf: array = array(1, 2.0); var xafpafai: array = array(1.0, 2); var xafpafaf: array = array(1.0, 2.0); +var ivispai = vec2(1); +var ivfspaf = vec2(1.0); +var ivis_ai = vec2(1); +var ivus_ai = vec2(1); +var ivfs_ai = vec2(1); +var ivfs_af = vec2(1.0); + +var iafafaf = array(1.0, 2.0); +var iafaiai = array(1, 2); + +var iafpafaf = array(1.0, 2.0); +var iafpaiaf = array(1, 2.0); +var iafpafai = array(1.0, 2); + fn all_constant_arguments() { var xvipaiai: vec2 = vec2(42, 43); var xvupaiai: vec2 = vec2(44, 45); diff --git a/naga/tests/in/const_assert.wgsl b/naga/tests/in/const_assert.wgsl new file mode 100644 index 0000000000..23f57fbb1a --- /dev/null +++ b/naga/tests/in/const_assert.wgsl @@ -0,0 +1,11 @@ +// Sourced from https://www.w3.org/TR/WGSL/#const-assert-statement +const x = 1; +const y = 2; +const_assert x < y; // valid at module-scope. +const_assert(y != 0); // parentheses are optional. + +fn foo() { + const z = x + y - 2; + const_assert z > 0; // valid in functions. + const_assert(z > 0); +} \ No newline at end of file diff --git a/naga/tests/in/cross.wgsl b/naga/tests/in/cross.wgsl new file mode 100644 index 0000000000..cfdd7622c3 --- /dev/null +++ b/naga/tests/in/cross.wgsl @@ -0,0 +1,4 @@ +// NOTE: invalid combinations are tested in the `validation::bad_cross_builtin_args` test. +@compute @workgroup_size(1) fn main() { + let a = cross(vec3(0., 1., 2.), vec3(0., 1., 2.)); +} diff --git a/naga/tests/in/interpolate.wgsl b/naga/tests/in/interpolate.wgsl index 2f6967b3e7..11657f10b8 100644 --- a/naga/tests/in/interpolate.wgsl +++ b/naga/tests/in/interpolate.wgsl @@ -1,14 +1,20 @@ //TODO: merge with "interface"? +// NOTE: invalid combinations are tested in the +// `validation::incompatible_interpolation_and_sampling_types` test. struct FragmentInput { @builtin(position) position: vec4, @location(0) @interpolate(flat) _flat : u32, - @location(1) @interpolate(linear) _linear : f32, - @location(2) @interpolate(linear, centroid) linear_centroid : vec2, - @location(3) @interpolate(linear, sample) linear_sample : vec3, - @location(4) @interpolate(perspective) perspective : vec4, - @location(5) @interpolate(perspective, centroid) perspective_centroid : f32, - @location(6) @interpolate(perspective, sample) perspective_sample : f32, + @location(1) @interpolate(flat, first) flat_first : u32, + @location(2) @interpolate(flat, either) flat_either : u32, + @location(3) @interpolate(linear) _linear : f32, + @location(4) @interpolate(linear, centroid) linear_centroid : vec2, + @location(6) @interpolate(linear, sample) linear_sample : vec3, + @location(7) @interpolate(linear, center) linear_center : vec3, + @location(8) @interpolate(perspective) perspective : vec4, + @location(9) @interpolate(perspective, centroid) perspective_centroid : f32, + @location(10) @interpolate(perspective, sample) perspective_sample : f32, + @location(11) @interpolate(perspective, center) perspective_center : f32, } @vertex @@ -17,12 +23,16 @@ fn vert_main() -> FragmentInput { out.position = vec4(2.0, 4.0, 5.0, 6.0); out._flat = 8u; + out.flat_first = 9u; + out.flat_either = 10u; out._linear = 27.0; out.linear_centroid = vec2(64.0, 125.0); out.linear_sample = vec3(216.0, 343.0, 512.0); + out.linear_center = vec3(255.0, 511.0, 1024.0); out.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0); out.perspective_centroid = 2197.0; out.perspective_sample = 2744.0; + out.perspective_center = 2812.0; return out; } diff --git a/naga/tests/in/interpolate_compat.param.ron b/naga/tests/in/interpolate_compat.param.ron new file mode 100644 index 0000000000..b6d629c4ea --- /dev/null +++ b/naga/tests/in/interpolate_compat.param.ron @@ -0,0 +1,15 @@ +( + spv: ( + version: (1, 0), + capabilities: [ Shader, SampleRateShading ], + debug: true, + force_point_size: true, + adjust_coordinate_space: true, + ), + glsl: ( + version: Desktop(400), + writer_flags: (""), + binding_map: {}, + zero_initialize_workgroup_memory: true, + ), +) diff --git a/naga/tests/in/interpolate_compat.wgsl b/naga/tests/in/interpolate_compat.wgsl new file mode 100644 index 0000000000..9ba6e7b818 --- /dev/null +++ b/naga/tests/in/interpolate_compat.wgsl @@ -0,0 +1,43 @@ +// NOTE: This is basically the same as `interpolate.wgsl`, except for the removal of +// `@interpolate(flat, first)`, which is unsupported in GLSL and `compat`. + +// NOTE: invalid combinations are tested in the +// `validation::incompatible_interpolation_and_sampling_types` test. +struct FragmentInput { + @builtin(position) position: vec4, + @location(0) @interpolate(flat) _flat : u32, + // NOTE: not supported in `compat` or GLSL + // // @location(1) @interpolate(flat, first) flat_first : u32, + @location(2) @interpolate(flat, either) flat_either : u32, + @location(3) @interpolate(linear) _linear : f32, + @location(4) @interpolate(linear, centroid) linear_centroid : vec2, + @location(6) @interpolate(linear, sample) linear_sample : vec3, + @location(7) @interpolate(linear, center) linear_center : vec3, + @location(8) @interpolate(perspective) perspective : vec4, + @location(9) @interpolate(perspective, centroid) perspective_centroid : f32, + @location(10) @interpolate(perspective, sample) perspective_sample : f32, + @location(11) @interpolate(perspective, center) perspective_center : f32, +} + +@vertex +fn vert_main() -> FragmentInput { + var out: FragmentInput; + + out.position = vec4(2.0, 4.0, 5.0, 6.0); + out._flat = 8u; + // out.flat_first = 9u; + out.flat_either = 10u; + out._linear = 27.0; + out.linear_centroid = vec2(64.0, 125.0); + out.linear_sample = vec3(216.0, 343.0, 512.0); + out.linear_center = vec3(255.0, 511.0, 1024.0); + out.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0); + out.perspective_centroid = 2197.0; + out.perspective_sample = 2744.0; + out.perspective_center = 2812.0; + + return out; +} + +@fragment +fn frag_main(val : FragmentInput) { } diff --git a/naga/tests/in/local-const.param.ron b/naga/tests/in/local-const.param.ron new file mode 100644 index 0000000000..dd626a0f31 --- /dev/null +++ b/naga/tests/in/local-const.param.ron @@ -0,0 +1 @@ +() \ No newline at end of file diff --git a/naga/tests/in/local-const.wgsl b/naga/tests/in/local-const.wgsl new file mode 100644 index 0000000000..18c932e1e0 --- /dev/null +++ b/naga/tests/in/local-const.wgsl @@ -0,0 +1,26 @@ +const ga = 4; // AbstractInt with a value of 4. +const gb : i32 = 4; // i32 with a value of 4. +const gc : u32 = 4; // u32 with a value of 4. +const gd : f32 = 4; // f32 with a value of 4. +const ge = vec3(ga, ga, ga); // vec3 of AbstractInt with a value of (4, 4, 4). +const gf = 2.0; // AbstractFloat with a value of 2. + +fn const_in_fn() { + const a = 4; // AbstractInt with a value of 4. + const b: i32 = 4; // i32 with a value of 4. + const c: u32 = 4; // u32 with a value of 4. + const d: f32 = 4; // f32 with a value of 4. + const e = vec3(a, a, a); // vec3 of AbstractInt with a value of (4, 4, 4). + const f = 2.0; // AbstractFloat with a value of 2. + // TODO: Make it per spec, currently not possible + // because naga does not support automatic conversions + // of Abstract types + + // Check that we can access global constants + const ag = ga; + const bg = gb; + const cg = gc; + const dg = gd; + const eg = ge; + const fg = gf; +} diff --git a/naga/tests/in/spv/atomic_exchange.spv b/naga/tests/in/spv/atomic_exchange.spv new file mode 100644 index 0000000000..cc64ce9aa8 Binary files /dev/null and b/naga/tests/in/spv/atomic_exchange.spv differ diff --git a/naga/tests/in/spv/atomic_exchange.spvasm b/naga/tests/in/spv/atomic_exchange.spvasm new file mode 100644 index 0000000000..09258f0584 --- /dev/null +++ b/naga/tests/in/spv/atomic_exchange.spvasm @@ -0,0 +1,88 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google rspirv; 0 +; Bound: 63 +; Schema: 0 + OpCapability Shader + OpCapability VulkanMemoryModel + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %1 "stage::test_atomic_exchange" %2 %3 + OpExecutionMode %1 LocalSize 32 1 1 + OpMemberDecorate %_struct_11 0 Offset 0 + OpMemberDecorate %_struct_11 1 Offset 4 + OpDecorate %_struct_12 Block + OpMemberDecorate %_struct_12 0 Offset 0 + OpDecorate %2 Binding 0 + OpDecorate %2 DescriptorSet 0 + OpDecorate %3 NonWritable + OpDecorate %3 Binding 1 + OpDecorate %3 DescriptorSet 0 + %uint = OpTypeInt 32 0 + %void = OpTypeVoid + %15 = OpTypeFunction %void + %bool = OpTypeBool + %uint_0 = OpConstant %uint 0 + %uint_2 = OpConstant %uint 2 + %false = OpConstantFalse %bool +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + %uint_1 = OpConstant %uint 1 + %_struct_11 = OpTypeStruct %uint %uint + %22 = OpUndef %_struct_11 + %int = OpTypeInt 32 1 + %true = OpConstantTrue %bool + %_struct_12 = OpTypeStruct %uint +%_ptr_StorageBuffer__struct_12 = OpTypePointer StorageBuffer %_struct_12 + %2 = OpVariable %_ptr_StorageBuffer__struct_12 StorageBuffer + %3 = OpVariable %_ptr_StorageBuffer__struct_12 StorageBuffer + %26 = OpUndef %uint + %1 = OpFunction %void None %15 + %27 = OpLabel + %28 = OpAccessChain %_ptr_StorageBuffer_uint %2 %uint_0 + %29 = OpAccessChain %_ptr_StorageBuffer_uint %3 %uint_0 + %30 = OpLoad %uint %29 + %31 = OpCompositeConstruct %_struct_11 %uint_0 %30 + OpBranch %32 + %32 = OpLabel + %33 = OpPhi %_struct_11 %31 %27 %34 %35 + %36 = OpPhi %uint %uint_0 %27 %37 %35 + OpLoopMerge %38 %35 None + OpBranch %39 + %39 = OpLabel + %40 = OpCompositeExtract %uint %33 0 + %41 = OpCompositeExtract %uint %33 1 + %42 = OpULessThan %bool %40 %41 + OpSelectionMerge %43 None + OpBranchConditional %42 %44 %45 + %44 = OpLabel + %47 = OpIAdd %uint %40 %uint_1 + %49 = OpCompositeInsert %_struct_11 %47 %33 0 + %50 = OpCompositeConstruct %_struct_11 %uint_1 %40 + OpBranch %43 + %45 = OpLabel + %51 = OpCompositeInsert %_struct_11 %uint_0 %22 0 + OpBranch %43 + %43 = OpLabel + %52 = OpPhi %_struct_11 %49 %44 %33 %45 + %53 = OpPhi %_struct_11 %50 %44 %51 %45 + %54 = OpCompositeExtract %uint %53 0 + %55 = OpBitcast %int %54 + OpSelectionMerge %56 None + OpSwitch %55 %57 0 %58 1 %59 + %57 = OpLabel + OpBranch %56 + %58 = OpLabel + OpBranch %56 + %59 = OpLabel + %60 = OpAtomicExchange %uint %28 %uint_2 %uint_0 %36 + %61 = OpIAdd %uint %36 %60 + OpBranch %56 + %56 = OpLabel + %62 = OpPhi %bool %false %57 %false %58 %true %59 + %34 = OpPhi %_struct_11 %22 %57 %22 %58 %52 %59 + %37 = OpPhi %uint %26 %57 %26 %58 %61 %59 + OpBranch %35 + %35 = OpLabel + OpBranchConditional %62 %32 %38 + %38 = OpLabel + OpReturn + OpFunctionEnd diff --git a/naga/tests/in/spv/atomic_i_add_sub.spv b/naga/tests/in/spv/atomic_i_add_sub.spv new file mode 100644 index 0000000000..8c26850400 Binary files /dev/null and b/naga/tests/in/spv/atomic_i_add_sub.spv differ diff --git a/naga/tests/in/spv/atomic_i_add_sub.spvasm b/naga/tests/in/spv/atomic_i_add_sub.spvasm new file mode 100644 index 0000000000..b23af99582 --- /dev/null +++ b/naga/tests/in/spv/atomic_i_add_sub.spvasm @@ -0,0 +1,51 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google rspirv; 0 +; Bound: 30 +; Schema: 0 + OpCapability Shader + OpCapability VulkanMemoryModel + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %1 "stage::test_atomic_i_add_sub" %2 %3 + OpExecutionMode %1 LocalSize 32 1 1 + OpDecorate %_runtimearr_uint ArrayStride 4 + OpDecorate %_struct_7 Block + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_8 Block + OpMemberDecorate %_struct_8 0 Offset 0 + OpDecorate %2 Binding 0 + OpDecorate %2 DescriptorSet 0 + OpDecorate %3 Binding 1 + OpDecorate %3 DescriptorSet 0 + %uint = OpTypeInt 32 0 + %void = OpTypeVoid + %11 = OpTypeFunction %void + %bool = OpTypeBool +%_runtimearr_uint = OpTypeRuntimeArray %uint + %_struct_7 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_7 = OpTypePointer StorageBuffer %_struct_7 + %uint_0 = OpConstant %uint 0 + %uint_2 = OpConstant %uint 2 +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + %_struct_8 = OpTypeStruct %uint +%_ptr_StorageBuffer__struct_8 = OpTypePointer StorageBuffer %_struct_8 + %2 = OpVariable %_ptr_StorageBuffer__struct_8 StorageBuffer + %3 = OpVariable %_ptr_StorageBuffer__struct_7 StorageBuffer + %1 = OpFunction %void None %11 + %19 = OpLabel + %20 = OpAccessChain %_ptr_StorageBuffer_uint %2 %uint_0 + %22 = OpArrayLength %uint %3 0 + %23 = OpAtomicIAdd %uint %20 %uint_2 %uint_0 %uint_2 + %24 = OpAtomicISub %uint %20 %uint_2 %uint_0 %23 + %25 = OpULessThan %bool %23 %22 + OpSelectionMerge %26 None + OpBranchConditional %25 %27 %28 + %27 = OpLabel + %29 = OpAccessChain %_ptr_StorageBuffer_uint %3 %uint_0 %23 + OpStore %29 %24 + OpBranch %26 + %28 = OpLabel + OpBranch %26 + %26 = OpLabel + OpReturn + OpFunctionEnd diff --git a/naga/tests/in/spv/atomic_i_decrement.spv b/naga/tests/in/spv/atomic_i_decrement.spv new file mode 100644 index 0000000000..fda602ab55 Binary files /dev/null and b/naga/tests/in/spv/atomic_i_decrement.spv differ diff --git a/naga/tests/in/spv/atomic_i_decrement.spvasm b/naga/tests/in/spv/atomic_i_decrement.spvasm new file mode 100644 index 0000000000..cc125beec4 --- /dev/null +++ b/naga/tests/in/spv/atomic_i_decrement.spvasm @@ -0,0 +1,64 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google rspirv; 0 +; Bound: 42 +; Schema: 0 + OpCapability Shader + OpCapability VulkanMemoryModel + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %1 "stage::test_atomic_i_decrement" %2 %3 + OpExecutionMode %1 LocalSize 32 1 1 + OpDecorate %_runtimearr_uint ArrayStride 4 + OpDecorate %_struct_7 Block + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_8 Block + OpMemberDecorate %_struct_8 0 Offset 0 + OpDecorate %2 Binding 0 + OpDecorate %2 DescriptorSet 0 + OpDecorate %3 Binding 1 + OpDecorate %3 DescriptorSet 0 + %uint = OpTypeInt 32 0 + %void = OpTypeVoid + %11 = OpTypeFunction %void + %bool = OpTypeBool +%_runtimearr_uint = OpTypeRuntimeArray %uint + %_struct_7 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_7 = OpTypePointer StorageBuffer %_struct_7 + %uint_0 = OpConstant %uint 0 + %uint_2 = OpConstant %uint 2 + %false = OpConstantFalse %bool +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + %true = OpConstantTrue %bool + %_struct_8 = OpTypeStruct %uint +%_ptr_StorageBuffer__struct_8 = OpTypePointer StorageBuffer %_struct_8 + %2 = OpVariable %_ptr_StorageBuffer__struct_8 StorageBuffer + %3 = OpVariable %_ptr_StorageBuffer__struct_7 StorageBuffer + %1 = OpFunction %void None %11 + %21 = OpLabel + %22 = OpAccessChain %_ptr_StorageBuffer_uint %2 %uint_0 + %24 = OpArrayLength %uint %3 0 + OpBranch %25 + %25 = OpLabel + OpLoopMerge %26 %27 None + OpBranch %28 + %28 = OpLabel + %29 = OpAtomicIDecrement %uint %22 %uint_2 %uint_0 + %30 = OpULessThan %bool %29 %24 + OpSelectionMerge %31 None + OpBranchConditional %30 %32 %33 + %32 = OpLabel + %34 = OpAccessChain %_ptr_StorageBuffer_uint %3 %uint_0 %29 + OpStore %34 %29 + %35 = OpIEqual %bool %29 %uint_0 + %41 = OpSelect %bool %35 %false %true + OpBranch %31 + %33 = OpLabel + OpBranch %31 + %31 = OpLabel + %40 = OpPhi %bool %41 %32 %false %33 + OpBranch %27 + %27 = OpLabel + OpBranchConditional %40 %25 %26 + %26 = OpLabel + OpReturn + OpFunctionEnd diff --git a/naga/tests/in/spv/atomic_i_increment.spvasm b/naga/tests/in/spv/atomic_i_increment.spvasm index 4586102d23..c072ca2986 100644 --- a/naga/tests/in/spv/atomic_i_increment.spvasm +++ b/naga/tests/in/spv/atomic_i_increment.spvasm @@ -59,4 +59,3 @@ %26 = OpLabel OpReturn OpFunctionEnd - diff --git a/naga/tests/in/spv/atomic_load_and_store.spv b/naga/tests/in/spv/atomic_load_and_store.spv new file mode 100644 index 0000000000..e2e9ddfd0b Binary files /dev/null and b/naga/tests/in/spv/atomic_load_and_store.spv differ diff --git a/naga/tests/in/spv/atomic_load_and_store.spvasm b/naga/tests/in/spv/atomic_load_and_store.spvasm new file mode 100644 index 0000000000..f65600c437 --- /dev/null +++ b/naga/tests/in/spv/atomic_load_and_store.spvasm @@ -0,0 +1,86 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google rspirv; 0 +; Bound: 60 +; Schema: 0 + OpCapability Shader + OpCapability VulkanMemoryModel + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %1 "stage::test_atomic_load_and_store" %2 %3 + OpExecutionMode %1 LocalSize 32 1 1 + OpMemberDecorate %_struct_11 0 Offset 0 + OpMemberDecorate %_struct_11 1 Offset 4 + OpDecorate %_struct_12 Block + OpMemberDecorate %_struct_12 0 Offset 0 + OpDecorate %2 Binding 0 + OpDecorate %2 DescriptorSet 0 + OpDecorate %3 NonWritable + OpDecorate %3 Binding 1 + OpDecorate %3 DescriptorSet 0 + %uint = OpTypeInt 32 0 + %void = OpTypeVoid + %15 = OpTypeFunction %void + %bool = OpTypeBool + %uint_0 = OpConstant %uint 0 + %uint_2 = OpConstant %uint 2 + %false = OpConstantFalse %bool +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + %uint_1 = OpConstant %uint 1 + %_struct_11 = OpTypeStruct %uint %uint + %22 = OpUndef %_struct_11 + %int = OpTypeInt 32 1 + %true = OpConstantTrue %bool + %_struct_12 = OpTypeStruct %uint +%_ptr_StorageBuffer__struct_12 = OpTypePointer StorageBuffer %_struct_12 + %2 = OpVariable %_ptr_StorageBuffer__struct_12 StorageBuffer + %3 = OpVariable %_ptr_StorageBuffer__struct_12 StorageBuffer + %1 = OpFunction %void None %15 + %26 = OpLabel + %27 = OpAccessChain %_ptr_StorageBuffer_uint %2 %uint_0 + %28 = OpAccessChain %_ptr_StorageBuffer_uint %3 %uint_0 + %29 = OpLoad %uint %28 + %30 = OpCompositeConstruct %_struct_11 %uint_0 %29 + OpBranch %31 + %31 = OpLabel + %32 = OpPhi %_struct_11 %30 %26 %33 %34 + OpLoopMerge %35 %34 None + OpBranch %36 + %36 = OpLabel + %37 = OpCompositeExtract %uint %32 0 + %38 = OpCompositeExtract %uint %32 1 + %39 = OpULessThan %bool %37 %38 + OpSelectionMerge %40 None + OpBranchConditional %39 %41 %42 + %41 = OpLabel + %44 = OpIAdd %uint %37 %uint_1 + %46 = OpCompositeInsert %_struct_11 %44 %32 0 + %47 = OpCompositeConstruct %_struct_11 %uint_1 %37 + OpBranch %40 + %42 = OpLabel + %48 = OpCompositeInsert %_struct_11 %uint_0 %22 0 + OpBranch %40 + %40 = OpLabel + %49 = OpPhi %_struct_11 %46 %41 %32 %42 + %50 = OpPhi %_struct_11 %47 %41 %48 %42 + %51 = OpCompositeExtract %uint %50 0 + %52 = OpBitcast %int %51 + OpSelectionMerge %53 None + OpSwitch %52 %54 0 %55 1 %56 + %54 = OpLabel + OpBranch %53 + %55 = OpLabel + OpBranch %53 + %56 = OpLabel + %57 = OpAtomicLoad %uint %27 %uint_2 %uint_0 + %58 = OpIAdd %uint %57 %uint_2 + OpAtomicStore %27 %uint_2 %uint_0 %58 + OpBranch %53 + %53 = OpLabel + %59 = OpPhi %bool %false %54 %false %55 %true %56 + %33 = OpPhi %_struct_11 %22 %54 %22 %55 %49 %56 + OpBranch %34 + %34 = OpLabel + OpBranchConditional %59 %31 %35 + %35 = OpLabel + OpReturn + OpFunctionEnd diff --git a/naga/tests/in/type-alias.wgsl b/naga/tests/in/type-alias.wgsl index 69c1eae4ef..cdc78451be 100644 --- a/naga/tests/in/type-alias.wgsl +++ b/naga/tests/in/type-alias.wgsl @@ -2,6 +2,8 @@ alias FVec3 = vec3; alias IVec3 = vec3i; alias Mat2 = mat2x2; alias Mat3 = mat3x3f; +alias I32 = i32; +alias F32 = f32; fn main() { let a = FVec3(0.0, 0.0, 0.0); @@ -12,4 +14,7 @@ fn main() { let f = Mat2(1.0, 2.0, 3.0, 4.0); let g = Mat3(a, a, a); + + let h = vec2(); + let i = mat2x2(); } diff --git a/naga/tests/out/analysis/access.info.ron b/naga/tests/out/analysis/access.info.ron index 52b0c020eb..308bb1a8b6 100644 --- a/naga/tests/out/analysis/access.info.ron +++ b/naga/tests/out/analysis/access.info.ron @@ -5,6 +5,7 @@ ("DATA | SIZED | COPY | IO_SHAREABLE | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("DATA | SIZED | COPY | IO_SHAREABLE | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("DATA | SIZED | COPY | IO_SHAREABLE | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), + ("DATA | SIZED | COPY | IO_SHAREABLE | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("DATA | SIZED | COPY | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("DATA | SIZED | COPY | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("DATA | SIZED | COPY | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), @@ -20,7 +21,6 @@ ("DATA | SIZED | COPY | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("DATA | SIZED | COPY | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("DATA | SIZED | COPY | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), - ("DATA | SIZED | COPY | IO_SHAREABLE | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("SIZED | COPY | ARGUMENT"), ("DATA | SIZED | COPY | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), ("DATA | SIZED | COPY | HOST_SHAREABLE | ARGUMENT | CONSTRUCTIBLE"), @@ -110,7 +110,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 15, + base: 16, space: Uniform, )), ), @@ -122,7 +122,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 14, + base: 15, space: Uniform, )), ), @@ -133,7 +133,7 @@ ), ref_count: 0, assignable_global: None, - ty: Handle(14), + ty: Handle(15), ), ( uniformity: ( @@ -143,7 +143,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 15, + base: 16, space: Uniform, )), ), @@ -155,7 +155,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 14, + base: 15, space: Uniform, )), ), @@ -198,7 +198,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 15, + base: 16, space: Uniform, )), ), @@ -210,7 +210,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 14, + base: 15, space: Uniform, )), ), @@ -262,7 +262,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 15, + base: 16, space: Uniform, )), ), @@ -274,7 +274,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 14, + base: 15, space: Uniform, )), ), @@ -330,7 +330,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 15, + base: 16, space: Uniform, )), ), @@ -342,7 +342,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 14, + base: 15, space: Uniform, )), ), @@ -407,7 +407,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 15, + base: 16, space: Uniform, )), ), @@ -419,7 +419,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 14, + base: 15, space: Uniform, )), ), @@ -484,7 +484,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 15, + base: 16, space: Uniform, )), ), @@ -496,7 +496,7 @@ ref_count: 1, assignable_global: Some(2), ty: Value(Pointer( - base: 14, + base: 15, space: Uniform, )), ), @@ -650,7 +650,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(14), + ty: Handle(15), ), ( uniformity: ( @@ -659,7 +659,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(15), + ty: Handle(16), ), ( uniformity: ( @@ -669,7 +669,7 @@ ref_count: 7, assignable_global: None, ty: Value(Pointer( - base: 15, + base: 16, space: Function, )), ), @@ -711,7 +711,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 14, + base: 15, space: Function, )), ), @@ -803,7 +803,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(14), + ty: Handle(15), ), ( uniformity: ( @@ -813,7 +813,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 14, + base: 15, space: Function, )), ), @@ -868,7 +868,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 14, + base: 15, space: Function, )), ), @@ -932,7 +932,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 14, + base: 15, space: Function, )), ), @@ -988,7 +988,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 14, + base: 15, space: Function, )), ), @@ -1053,7 +1053,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 14, + base: 15, space: Function, )), ), @@ -1118,7 +1118,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 14, + base: 15, space: Function, )), ), @@ -1267,7 +1267,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 19, + base: 20, space: Uniform, )), ), @@ -1279,7 +1279,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 18, + base: 19, space: Uniform, )), ), @@ -1290,7 +1290,7 @@ ), ref_count: 0, assignable_global: None, - ty: Handle(18), + ty: Handle(19), ), ( uniformity: ( @@ -1300,7 +1300,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 19, + base: 20, space: Uniform, )), ), @@ -1312,7 +1312,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 18, + base: 19, space: Uniform, )), ), @@ -1324,7 +1324,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 17, + base: 18, space: Uniform, )), ), @@ -1335,7 +1335,7 @@ ), ref_count: 0, assignable_global: None, - ty: Handle(17), + ty: Handle(18), ), ( uniformity: ( @@ -1345,7 +1345,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 19, + base: 20, space: Uniform, )), ), @@ -1357,7 +1357,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 18, + base: 19, space: Uniform, )), ), @@ -1369,7 +1369,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 17, + base: 18, space: Uniform, )), ), @@ -1412,7 +1412,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 19, + base: 20, space: Uniform, )), ), @@ -1424,7 +1424,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 18, + base: 19, space: Uniform, )), ), @@ -1436,7 +1436,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 17, + base: 18, space: Uniform, )), ), @@ -1488,7 +1488,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 19, + base: 20, space: Uniform, )), ), @@ -1500,7 +1500,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 18, + base: 19, space: Uniform, )), ), @@ -1512,7 +1512,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 17, + base: 18, space: Uniform, )), ), @@ -1568,7 +1568,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 19, + base: 20, space: Uniform, )), ), @@ -1580,7 +1580,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 18, + base: 19, space: Uniform, )), ), @@ -1592,7 +1592,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 17, + base: 18, space: Uniform, )), ), @@ -1657,7 +1657,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 19, + base: 20, space: Uniform, )), ), @@ -1669,7 +1669,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 18, + base: 19, space: Uniform, )), ), @@ -1681,7 +1681,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 17, + base: 18, space: Uniform, )), ), @@ -1746,7 +1746,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 19, + base: 20, space: Uniform, )), ), @@ -1758,7 +1758,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 18, + base: 19, space: Uniform, )), ), @@ -1770,7 +1770,7 @@ ref_count: 1, assignable_global: Some(4), ty: Value(Pointer( - base: 17, + base: 18, space: Uniform, )), ), @@ -1843,7 +1843,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(18), + ty: Handle(19), ), ( uniformity: ( @@ -1852,7 +1852,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(19), + ty: Handle(20), ), ( uniformity: ( @@ -1862,7 +1862,7 @@ ref_count: 8, assignable_global: None, ty: Value(Pointer( - base: 19, + base: 20, space: Function, )), ), @@ -1904,7 +1904,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 18, + base: 19, space: Function, )), ), @@ -1915,7 +1915,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(18), + ty: Handle(19), ), ( uniformity: ( @@ -1925,7 +1925,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 18, + base: 19, space: Function, )), ), @@ -1937,7 +1937,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 17, + base: 18, space: Function, )), ), @@ -2056,7 +2056,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(17), + ty: Handle(18), ), ( uniformity: ( @@ -2066,7 +2066,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 18, + base: 19, space: Function, )), ), @@ -2078,7 +2078,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 17, + base: 18, space: Function, )), ), @@ -2133,7 +2133,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 18, + base: 19, space: Function, )), ), @@ -2145,7 +2145,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 17, + base: 18, space: Function, )), ), @@ -2209,7 +2209,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 18, + base: 19, space: Function, )), ), @@ -2221,7 +2221,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 17, + base: 18, space: Function, )), ), @@ -2277,7 +2277,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 18, + base: 19, space: Function, )), ), @@ -2289,7 +2289,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 17, + base: 18, space: Function, )), ), @@ -2354,7 +2354,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 18, + base: 19, space: Function, )), ), @@ -2366,7 +2366,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 17, + base: 18, space: Function, )), ), @@ -2431,7 +2431,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 18, + base: 19, space: Function, )), ), @@ -2443,7 +2443,7 @@ ref_count: 1, assignable_global: None, ty: Value(Pointer( - base: 17, + base: 18, space: Function, )), ), @@ -2546,7 +2546,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(20), + ty: Handle(5), ), ], sampling: [], @@ -2594,7 +2594,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(20), + ty: Handle(5), ), ], sampling: [], @@ -2783,7 +2783,7 @@ ref_count: 3, assignable_global: None, ty: Value(Pointer( - base: 20, + base: 5, space: Function, )), ), @@ -2794,7 +2794,7 @@ ), ref_count: 0, assignable_global: None, - ty: Handle(20), + ty: Handle(5), ), ( uniformity: ( @@ -2816,7 +2816,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -2830,7 +2830,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 5, + base: 6, space: Storage( access: ("LOAD | STORE"), ), @@ -2843,7 +2843,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(5), + ty: Handle(6), ), ( uniformity: ( @@ -2853,7 +2853,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -2867,7 +2867,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 11, + base: 12, space: Storage( access: ("LOAD | STORE"), ), @@ -2880,7 +2880,7 @@ ), ref_count: 0, assignable_global: None, - ty: Handle(11), + ty: Handle(12), ), ( uniformity: ( @@ -2902,7 +2902,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -2916,7 +2916,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 5, + base: 6, space: Storage( access: ("LOAD | STORE"), ), @@ -2978,7 +2978,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -2992,7 +2992,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 12, + base: 13, space: Storage( access: ("LOAD | STORE"), ), @@ -3006,7 +3006,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -3020,7 +3020,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 12, + base: 13, space: Storage( access: ("LOAD | STORE"), ), @@ -3107,7 +3107,7 @@ ref_count: 1, assignable_global: Some(3), ty: Value(Pointer( - base: 16, + base: 17, space: Storage( access: ("LOAD | STORE"), ), @@ -3120,7 +3120,7 @@ ), ref_count: 0, assignable_global: None, - ty: Handle(16), + ty: Handle(17), ), ( uniformity: ( @@ -3130,7 +3130,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -3144,7 +3144,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 12, + base: 13, space: Storage( access: ("LOAD | STORE"), ), @@ -3185,7 +3185,7 @@ ), ref_count: 0, assignable_global: None, - ty: Handle(20), + ty: Handle(5), ), ( uniformity: ( @@ -3338,7 +3338,7 @@ ), ref_count: 0, assignable_global: None, - ty: Handle(20), + ty: Handle(5), ), ( uniformity: ( @@ -3435,7 +3435,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -3449,7 +3449,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 5, + base: 6, space: Storage( access: ("LOAD | STORE"), ), @@ -3511,7 +3511,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -3525,7 +3525,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 5, + base: 6, space: Storage( access: ("LOAD | STORE"), ), @@ -3646,7 +3646,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(5), + ty: Handle(6), ), ( uniformity: ( @@ -3656,7 +3656,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -3670,7 +3670,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 11, + base: 12, space: Storage( access: ("LOAD | STORE"), ), @@ -3737,7 +3737,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(11), + ty: Handle(12), ), ( uniformity: ( @@ -3747,7 +3747,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 13, + base: 14, space: Storage( access: ("LOAD | STORE"), ), @@ -3761,7 +3761,7 @@ ref_count: 1, assignable_global: Some(1), ty: Value(Pointer( - base: 12, + base: 13, space: Storage( access: ("LOAD | STORE"), ), @@ -3815,7 +3815,7 @@ ref_count: 1, assignable_global: Some(3), ty: Value(Pointer( - base: 16, + base: 17, space: Storage( access: ("LOAD | STORE"), ), @@ -3828,7 +3828,7 @@ ), ref_count: 1, assignable_global: None, - ty: Handle(16), + ty: Handle(17), ), ( uniformity: ( diff --git a/naga/tests/out/glsl/access.foo_frag.Fragment.glsl b/naga/tests/out/glsl/access.foo_frag.Fragment.glsl index 3d52fa56b0..aacdda0130 100644 --- a/naga/tests/out/glsl/access.foo_frag.Fragment.glsl +++ b/naga/tests/out/glsl/access.foo_frag.Fragment.glsl @@ -26,7 +26,7 @@ layout(std430) buffer Bar_block_0Fragment { AlignedWrapper data[]; } _group_0_binding_0_fs; -layout(std430) buffer type_12_block_1Fragment { ivec2 _group_0_binding_2_fs; }; +layout(std430) buffer type_13_block_1Fragment { ivec2 _group_0_binding_2_fs; }; layout(location = 0) out vec4 _fs2p_location0; diff --git a/naga/tests/out/glsl/access.foo_vert.Vertex.glsl b/naga/tests/out/glsl/access.foo_vert.Vertex.glsl index edc7ce1e6b..d4a9b92945 100644 --- a/naga/tests/out/glsl/access.foo_vert.Vertex.glsl +++ b/naga/tests/out/glsl/access.foo_vert.Vertex.glsl @@ -28,7 +28,7 @@ layout(std430) buffer Bar_block_0Vertex { uniform Baz_block_1Vertex { Baz _group_0_binding_1_vs; }; -layout(std430) buffer type_12_block_2Vertex { ivec2 _group_0_binding_2_vs; }; +layout(std430) buffer type_13_block_2Vertex { ivec2 _group_0_binding_2_vs; }; uniform MatCx2InArray_block_3Vertex { MatCx2InArray _group_0_binding_3_vs; }; diff --git a/naga/tests/out/glsl/cross.main.Compute.glsl b/naga/tests/out/glsl/cross.main.Compute.glsl new file mode 100644 index 0000000000..a4950274e3 --- /dev/null +++ b/naga/tests/out/glsl/cross.main.Compute.glsl @@ -0,0 +1,12 @@ +#version 310 es + +precision highp float; +precision highp int; + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + + +void main() { + vec3 a = cross(vec3(0.0, 1.0, 2.0), vec3(0.0, 1.0, 2.0)); +} + diff --git a/naga/tests/out/glsl/interpolate.frag_main.Fragment.glsl b/naga/tests/out/glsl/interpolate.frag_main.Fragment.glsl index d1662da493..3f23f487f4 100644 --- a/naga/tests/out/glsl/interpolate.frag_main.Fragment.glsl +++ b/naga/tests/out/glsl/interpolate.frag_main.Fragment.glsl @@ -2,23 +2,31 @@ struct FragmentInput { vec4 position; uint _flat; + uint flat_first; + uint flat_either; float _linear; vec2 linear_centroid; vec3 linear_sample; + vec3 linear_center; vec4 perspective; float perspective_centroid; float perspective_sample; + float perspective_center; }; flat in uint _vs2fs_location0; -noperspective in float _vs2fs_location1; -noperspective centroid in vec2 _vs2fs_location2; -noperspective sample in vec3 _vs2fs_location3; -smooth in vec4 _vs2fs_location4; -smooth centroid in float _vs2fs_location5; -smooth sample in float _vs2fs_location6; +flat in uint _vs2fs_location1; +flat in uint _vs2fs_location2; +noperspective in float _vs2fs_location3; +noperspective centroid in vec2 _vs2fs_location4; +noperspective sample in vec3 _vs2fs_location6; +noperspective in vec3 _vs2fs_location7; +smooth in vec4 _vs2fs_location8; +smooth centroid in float _vs2fs_location9; +smooth sample in float _vs2fs_location10; +smooth in float _vs2fs_location11; void main() { - FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location1, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4, _vs2fs_location5, _vs2fs_location6); + FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location1, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4, _vs2fs_location6, _vs2fs_location7, _vs2fs_location8, _vs2fs_location9, _vs2fs_location10, _vs2fs_location11); return; } diff --git a/naga/tests/out/glsl/interpolate.vert_main.Vertex.glsl b/naga/tests/out/glsl/interpolate.vert_main.Vertex.glsl index f423a3dc18..1afe43a478 100644 --- a/naga/tests/out/glsl/interpolate.vert_main.Vertex.glsl +++ b/naga/tests/out/glsl/interpolate.vert_main.Vertex.glsl @@ -2,40 +2,56 @@ struct FragmentInput { vec4 position; uint _flat; + uint flat_first; + uint flat_either; float _linear; vec2 linear_centroid; vec3 linear_sample; + vec3 linear_center; vec4 perspective; float perspective_centroid; float perspective_sample; + float perspective_center; }; flat out uint _vs2fs_location0; -noperspective out float _vs2fs_location1; -noperspective centroid out vec2 _vs2fs_location2; -noperspective sample out vec3 _vs2fs_location3; -smooth out vec4 _vs2fs_location4; -smooth centroid out float _vs2fs_location5; -smooth sample out float _vs2fs_location6; +flat out uint _vs2fs_location1; +flat out uint _vs2fs_location2; +noperspective out float _vs2fs_location3; +noperspective centroid out vec2 _vs2fs_location4; +noperspective sample out vec3 _vs2fs_location6; +noperspective out vec3 _vs2fs_location7; +smooth out vec4 _vs2fs_location8; +smooth centroid out float _vs2fs_location9; +smooth sample out float _vs2fs_location10; +smooth out float _vs2fs_location11; void main() { - FragmentInput out_ = FragmentInput(vec4(0.0), 0u, 0.0, vec2(0.0), vec3(0.0), vec4(0.0), 0.0, 0.0); + FragmentInput out_ = FragmentInput(vec4(0.0), 0u, 0u, 0u, 0.0, vec2(0.0), vec3(0.0), vec3(0.0), vec4(0.0), 0.0, 0.0, 0.0); out_.position = vec4(2.0, 4.0, 5.0, 6.0); out_._flat = 8u; + out_.flat_first = 9u; + out_.flat_either = 10u; out_._linear = 27.0; out_.linear_centroid = vec2(64.0, 125.0); out_.linear_sample = vec3(216.0, 343.0, 512.0); + out_.linear_center = vec3(255.0, 511.0, 1024.0); out_.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0); out_.perspective_centroid = 2197.0; out_.perspective_sample = 2744.0; - FragmentInput _e30 = out_; - gl_Position = _e30.position; - _vs2fs_location0 = _e30._flat; - _vs2fs_location1 = _e30._linear; - _vs2fs_location2 = _e30.linear_centroid; - _vs2fs_location3 = _e30.linear_sample; - _vs2fs_location4 = _e30.perspective; - _vs2fs_location5 = _e30.perspective_centroid; - _vs2fs_location6 = _e30.perspective_sample; + out_.perspective_center = 2812.0; + FragmentInput _e41 = out_; + gl_Position = _e41.position; + _vs2fs_location0 = _e41._flat; + _vs2fs_location1 = _e41.flat_first; + _vs2fs_location2 = _e41.flat_either; + _vs2fs_location3 = _e41._linear; + _vs2fs_location4 = _e41.linear_centroid; + _vs2fs_location6 = _e41.linear_sample; + _vs2fs_location7 = _e41.linear_center; + _vs2fs_location8 = _e41.perspective; + _vs2fs_location9 = _e41.perspective_centroid; + _vs2fs_location10 = _e41.perspective_sample; + _vs2fs_location11 = _e41.perspective_center; return; } diff --git a/naga/tests/out/glsl/interpolate_compat.frag_main.Fragment.glsl b/naga/tests/out/glsl/interpolate_compat.frag_main.Fragment.glsl new file mode 100644 index 0000000000..ac7fad324f --- /dev/null +++ b/naga/tests/out/glsl/interpolate_compat.frag_main.Fragment.glsl @@ -0,0 +1,30 @@ +#version 400 core +struct FragmentInput { + vec4 position; + uint _flat; + uint flat_either; + float _linear; + vec2 linear_centroid; + vec3 linear_sample; + vec3 linear_center; + vec4 perspective; + float perspective_centroid; + float perspective_sample; + float perspective_center; +}; +flat in uint _vs2fs_location0; +flat in uint _vs2fs_location2; +noperspective in float _vs2fs_location3; +noperspective centroid in vec2 _vs2fs_location4; +noperspective sample in vec3 _vs2fs_location6; +noperspective in vec3 _vs2fs_location7; +smooth in vec4 _vs2fs_location8; +smooth centroid in float _vs2fs_location9; +smooth sample in float _vs2fs_location10; +smooth in float _vs2fs_location11; + +void main() { + FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4, _vs2fs_location6, _vs2fs_location7, _vs2fs_location8, _vs2fs_location9, _vs2fs_location10, _vs2fs_location11); + return; +} + diff --git a/naga/tests/out/glsl/interpolate_compat.vert_main.Vertex.glsl b/naga/tests/out/glsl/interpolate_compat.vert_main.Vertex.glsl new file mode 100644 index 0000000000..5b85026d79 --- /dev/null +++ b/naga/tests/out/glsl/interpolate_compat.vert_main.Vertex.glsl @@ -0,0 +1,53 @@ +#version 400 core +struct FragmentInput { + vec4 position; + uint _flat; + uint flat_either; + float _linear; + vec2 linear_centroid; + vec3 linear_sample; + vec3 linear_center; + vec4 perspective; + float perspective_centroid; + float perspective_sample; + float perspective_center; +}; +flat out uint _vs2fs_location0; +flat out uint _vs2fs_location2; +noperspective out float _vs2fs_location3; +noperspective centroid out vec2 _vs2fs_location4; +noperspective sample out vec3 _vs2fs_location6; +noperspective out vec3 _vs2fs_location7; +smooth out vec4 _vs2fs_location8; +smooth centroid out float _vs2fs_location9; +smooth sample out float _vs2fs_location10; +smooth out float _vs2fs_location11; + +void main() { + FragmentInput out_ = FragmentInput(vec4(0.0), 0u, 0u, 0.0, vec2(0.0), vec3(0.0), vec3(0.0), vec4(0.0), 0.0, 0.0, 0.0); + out_.position = vec4(2.0, 4.0, 5.0, 6.0); + out_._flat = 8u; + out_.flat_either = 10u; + out_._linear = 27.0; + out_.linear_centroid = vec2(64.0, 125.0); + out_.linear_sample = vec3(216.0, 343.0, 512.0); + out_.linear_center = vec3(255.0, 511.0, 1024.0); + out_.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0); + out_.perspective_centroid = 2197.0; + out_.perspective_sample = 2744.0; + out_.perspective_center = 2812.0; + FragmentInput _e39 = out_; + gl_Position = _e39.position; + _vs2fs_location0 = _e39._flat; + _vs2fs_location2 = _e39.flat_either; + _vs2fs_location3 = _e39._linear; + _vs2fs_location4 = _e39.linear_centroid; + _vs2fs_location6 = _e39.linear_sample; + _vs2fs_location7 = _e39.linear_center; + _vs2fs_location8 = _e39.perspective; + _vs2fs_location9 = _e39.perspective_centroid; + _vs2fs_location10 = _e39.perspective_sample; + _vs2fs_location11 = _e39.perspective_center; + return; +} + diff --git a/naga/tests/out/glsl/shadow.fs_main.Fragment.glsl b/naga/tests/out/glsl/shadow.fs_main.Fragment.glsl index 61c14561d5..ab7214380f 100644 --- a/naga/tests/out/glsl/shadow.fs_main.Fragment.glsl +++ b/naga/tests/out/glsl/shadow.fs_main.Fragment.glsl @@ -28,7 +28,7 @@ uniform Globals_block_0Fragment { Globals _group_0_binding_0_fs; }; uniform Entity_block_1Fragment { Entity _group_1_binding_0_fs; }; -layout(std430) readonly buffer type_6_block_2Fragment { Light _group_0_binding_1_fs[]; }; +layout(std430) readonly buffer type_8_block_2Fragment { Light _group_0_binding_1_fs[]; }; uniform highp sampler2DArrayShadow _group_0_binding_2_fs; diff --git a/naga/tests/out/glsl/shadow.fs_main_without_storage.Fragment.glsl b/naga/tests/out/glsl/shadow.fs_main_without_storage.Fragment.glsl index 57677c91a6..a9fcf31d56 100644 --- a/naga/tests/out/glsl/shadow.fs_main_without_storage.Fragment.glsl +++ b/naga/tests/out/glsl/shadow.fs_main_without_storage.Fragment.glsl @@ -28,7 +28,7 @@ uniform Globals_block_0Fragment { Globals _group_0_binding_0_fs; }; uniform Entity_block_1Fragment { Entity _group_1_binding_0_fs; }; -uniform type_7_block_2Fragment { Light _group_0_binding_1_fs[10]; }; +uniform type_9_block_2Fragment { Light _group_0_binding_1_fs[10]; }; uniform highp sampler2DArrayShadow _group_0_binding_2_fs; diff --git a/naga/tests/out/hlsl/cross.hlsl b/naga/tests/out/hlsl/cross.hlsl new file mode 100644 index 0000000000..96696c5066 --- /dev/null +++ b/naga/tests/out/hlsl/cross.hlsl @@ -0,0 +1,5 @@ +[numthreads(1, 1, 1)] +void main() +{ + float3 a = cross(float3(0.0, 1.0, 2.0), float3(0.0, 1.0, 2.0)); +} diff --git a/naga/tests/out/hlsl/cross.ron b/naga/tests/out/hlsl/cross.ron new file mode 100644 index 0000000000..a07b03300b --- /dev/null +++ b/naga/tests/out/hlsl/cross.ron @@ -0,0 +1,12 @@ +( + vertex:[ + ], + fragment:[ + ], + compute:[ + ( + entry_point:"main", + target_profile:"cs_5_1", + ), + ], +) diff --git a/naga/tests/out/hlsl/image.hlsl b/naga/tests/out/hlsl/image.hlsl index 1b41aa56eb..5ad6d3d2c0 100644 --- a/naga/tests/out/hlsl/image.hlsl +++ b/naga/tests/out/hlsl/image.hlsl @@ -3,9 +3,9 @@ Texture2DMS image_multisampled_src : register(t3); Texture2DMS image_depth_multisampled_src : register(t4); RWTexture2D image_storage_src : register(u1); Texture2DArray image_array_src : register(t5); -RWTexture1D image_dup_src : register(u6); +RWTexture1D image_dup_src : register(u6); Texture1D image_1d_src : register(t7); -RWTexture1D image_dst : register(u2); +RWTexture1D image_dst : register(u2); Texture1D image_1d : register(t0); Texture2D image_2d : register(t1); Texture2D image_2d_u32_ : register(t2); diff --git a/naga/tests/out/hlsl/interpolate.hlsl b/naga/tests/out/hlsl/interpolate.hlsl index 29fd45e0ff..ebb6e83477 100644 --- a/naga/tests/out/hlsl/interpolate.hlsl +++ b/naga/tests/out/hlsl/interpolate.hlsl @@ -1,33 +1,45 @@ struct FragmentInput { float4 position : SV_Position; nointerpolation uint _flat : LOC0; - noperspective float _linear : LOC1; - noperspective centroid float2 linear_centroid : LOC2; - noperspective sample float3 linear_sample : LOC3; - float4 perspective : LOC4; - centroid float perspective_centroid : LOC5; - sample float perspective_sample : LOC6; + nointerpolation uint flat_first : LOC1; + nointerpolation uint flat_either : LOC2; + noperspective float _linear : LOC3; + noperspective centroid float2 linear_centroid : LOC4; + noperspective sample float3 linear_sample : LOC6; + noperspective float3 linear_center : LOC7; + float4 perspective : LOC8; + centroid float perspective_centroid : LOC9; + sample float perspective_sample : LOC10; + float perspective_center : LOC11; }; struct VertexOutput_vert_main { nointerpolation uint _flat : LOC0; - noperspective float _linear : LOC1; - noperspective centroid float2 linear_centroid : LOC2; - noperspective sample float3 linear_sample : LOC3; - float4 perspective : LOC4; - centroid float perspective_centroid : LOC5; - sample float perspective_sample : LOC6; + nointerpolation uint flat_first : LOC1; + nointerpolation uint flat_either : LOC2; + noperspective float _linear : LOC3; + noperspective centroid float2 linear_centroid : LOC4; + noperspective sample float3 linear_sample : LOC6; + noperspective float3 linear_center : LOC7; + float4 perspective : LOC8; + centroid float perspective_centroid : LOC9; + sample float perspective_sample : LOC10; + float perspective_center : LOC11; float4 position : SV_Position; }; struct FragmentInput_frag_main { nointerpolation uint _flat_1 : LOC0; - noperspective float _linear_1 : LOC1; - noperspective centroid float2 linear_centroid_1 : LOC2; - noperspective sample float3 linear_sample_1 : LOC3; - float4 perspective_1 : LOC4; - centroid float perspective_centroid_1 : LOC5; - sample float perspective_sample_1 : LOC6; + nointerpolation uint flat_first_1 : LOC1; + nointerpolation uint flat_either_1 : LOC2; + noperspective float _linear_1 : LOC3; + noperspective centroid float2 linear_centroid_1 : LOC4; + noperspective sample float3 linear_sample_1 : LOC6; + noperspective float3 linear_center_1 : LOC7; + float4 perspective_1 : LOC8; + centroid float perspective_centroid_1 : LOC9; + sample float perspective_sample_1 : LOC10; + float perspective_center_1 : LOC11; float4 position_1 : SV_Position; }; @@ -37,20 +49,24 @@ VertexOutput_vert_main vert_main() out_.position = float4(2.0, 4.0, 5.0, 6.0); out_._flat = 8u; + out_.flat_first = 9u; + out_.flat_either = 10u; out_._linear = 27.0; out_.linear_centroid = float2(64.0, 125.0); out_.linear_sample = float3(216.0, 343.0, 512.0); + out_.linear_center = float3(255.0, 511.0, 1024.0); out_.perspective = float4(729.0, 1000.0, 1331.0, 1728.0); out_.perspective_centroid = 2197.0; out_.perspective_sample = 2744.0; - FragmentInput _e30 = out_; - const FragmentInput fragmentinput = _e30; - const VertexOutput_vert_main fragmentinput_1 = { fragmentinput._flat, fragmentinput._linear, fragmentinput.linear_centroid, fragmentinput.linear_sample, fragmentinput.perspective, fragmentinput.perspective_centroid, fragmentinput.perspective_sample, fragmentinput.position }; + out_.perspective_center = 2812.0; + FragmentInput _e41 = out_; + const FragmentInput fragmentinput = _e41; + const VertexOutput_vert_main fragmentinput_1 = { fragmentinput._flat, fragmentinput.flat_first, fragmentinput.flat_either, fragmentinput._linear, fragmentinput.linear_centroid, fragmentinput.linear_sample, fragmentinput.linear_center, fragmentinput.perspective, fragmentinput.perspective_centroid, fragmentinput.perspective_sample, fragmentinput.perspective_center, fragmentinput.position }; return fragmentinput_1; } void frag_main(FragmentInput_frag_main fragmentinput_frag_main) { - FragmentInput val = { fragmentinput_frag_main.position_1, fragmentinput_frag_main._flat_1, fragmentinput_frag_main._linear_1, fragmentinput_frag_main.linear_centroid_1, fragmentinput_frag_main.linear_sample_1, fragmentinput_frag_main.perspective_1, fragmentinput_frag_main.perspective_centroid_1, fragmentinput_frag_main.perspective_sample_1 }; + FragmentInput val = { fragmentinput_frag_main.position_1, fragmentinput_frag_main._flat_1, fragmentinput_frag_main.flat_first_1, fragmentinput_frag_main.flat_either_1, fragmentinput_frag_main._linear_1, fragmentinput_frag_main.linear_centroid_1, fragmentinput_frag_main.linear_sample_1, fragmentinput_frag_main.linear_center_1, fragmentinput_frag_main.perspective_1, fragmentinput_frag_main.perspective_centroid_1, fragmentinput_frag_main.perspective_sample_1, fragmentinput_frag_main.perspective_center_1 }; return; } diff --git a/naga/tests/out/hlsl/interpolate_compat.hlsl b/naga/tests/out/hlsl/interpolate_compat.hlsl new file mode 100644 index 0000000000..85f1bb001c --- /dev/null +++ b/naga/tests/out/hlsl/interpolate_compat.hlsl @@ -0,0 +1,68 @@ +struct FragmentInput { + float4 position : SV_Position; + nointerpolation uint _flat : LOC0; + nointerpolation uint flat_either : LOC2; + noperspective float _linear : LOC3; + noperspective centroid float2 linear_centroid : LOC4; + noperspective sample float3 linear_sample : LOC6; + noperspective float3 linear_center : LOC7; + float4 perspective : LOC8; + centroid float perspective_centroid : LOC9; + sample float perspective_sample : LOC10; + float perspective_center : LOC11; +}; + +struct VertexOutput_vert_main { + nointerpolation uint _flat : LOC0; + nointerpolation uint flat_either : LOC2; + noperspective float _linear : LOC3; + noperspective centroid float2 linear_centroid : LOC4; + noperspective sample float3 linear_sample : LOC6; + noperspective float3 linear_center : LOC7; + float4 perspective : LOC8; + centroid float perspective_centroid : LOC9; + sample float perspective_sample : LOC10; + float perspective_center : LOC11; + float4 position : SV_Position; +}; + +struct FragmentInput_frag_main { + nointerpolation uint _flat_1 : LOC0; + nointerpolation uint flat_either_1 : LOC2; + noperspective float _linear_1 : LOC3; + noperspective centroid float2 linear_centroid_1 : LOC4; + noperspective sample float3 linear_sample_1 : LOC6; + noperspective float3 linear_center_1 : LOC7; + float4 perspective_1 : LOC8; + centroid float perspective_centroid_1 : LOC9; + sample float perspective_sample_1 : LOC10; + float perspective_center_1 : LOC11; + float4 position_1 : SV_Position; +}; + +VertexOutput_vert_main vert_main() +{ + FragmentInput out_ = (FragmentInput)0; + + out_.position = float4(2.0, 4.0, 5.0, 6.0); + out_._flat = 8u; + out_.flat_either = 10u; + out_._linear = 27.0; + out_.linear_centroid = float2(64.0, 125.0); + out_.linear_sample = float3(216.0, 343.0, 512.0); + out_.linear_center = float3(255.0, 511.0, 1024.0); + out_.perspective = float4(729.0, 1000.0, 1331.0, 1728.0); + out_.perspective_centroid = 2197.0; + out_.perspective_sample = 2744.0; + out_.perspective_center = 2812.0; + FragmentInput _e39 = out_; + const FragmentInput fragmentinput = _e39; + const VertexOutput_vert_main fragmentinput_1 = { fragmentinput._flat, fragmentinput.flat_either, fragmentinput._linear, fragmentinput.linear_centroid, fragmentinput.linear_sample, fragmentinput.linear_center, fragmentinput.perspective, fragmentinput.perspective_centroid, fragmentinput.perspective_sample, fragmentinput.perspective_center, fragmentinput.position }; + return fragmentinput_1; +} + +void frag_main(FragmentInput_frag_main fragmentinput_frag_main) +{ + FragmentInput val = { fragmentinput_frag_main.position_1, fragmentinput_frag_main._flat_1, fragmentinput_frag_main.flat_either_1, fragmentinput_frag_main._linear_1, fragmentinput_frag_main.linear_centroid_1, fragmentinput_frag_main.linear_sample_1, fragmentinput_frag_main.linear_center_1, fragmentinput_frag_main.perspective_1, fragmentinput_frag_main.perspective_centroid_1, fragmentinput_frag_main.perspective_sample_1, fragmentinput_frag_main.perspective_center_1 }; + return; +} diff --git a/naga/tests/out/hlsl/interpolate_compat.ron b/naga/tests/out/hlsl/interpolate_compat.ron new file mode 100644 index 0000000000..d0046b04dd --- /dev/null +++ b/naga/tests/out/hlsl/interpolate_compat.ron @@ -0,0 +1,16 @@ +( + vertex:[ + ( + entry_point:"vert_main", + target_profile:"vs_5_1", + ), + ], + fragment:[ + ( + entry_point:"frag_main", + target_profile:"ps_5_1", + ), + ], + compute:[ + ], +) diff --git a/naga/tests/out/ir/access.compact.ron b/naga/tests/out/ir/access.compact.ron index fd9405f2d0..1b95742ff2 100644 --- a/naga/tests/out/ir/access.compact.ron +++ b/naga/tests/out/ir/access.compact.ron @@ -64,6 +64,13 @@ span: 8, ), ), + ( + name: None, + inner: Scalar(( + kind: Float, + width: 4, + )), + ), ( name: None, inner: Matrix( @@ -89,7 +96,7 @@ ( name: None, inner: Array( - base: 6, + base: 7, size: Constant(2), stride: 16, ), @@ -104,7 +111,7 @@ ( name: None, inner: Array( - base: 8, + base: 9, size: Constant(10), stride: 4, ), @@ -122,7 +129,7 @@ ( name: None, inner: Array( - base: 10, + base: 11, size: Constant(2), stride: 8, ), @@ -141,37 +148,37 @@ members: [ ( name: Some("_matrix"), - ty: 5, + ty: 6, binding: None, offset: 0, ), ( name: Some("matrix_array"), - ty: 7, + ty: 8, binding: None, offset: 64, ), ( name: Some("atom"), - ty: 8, + ty: 9, binding: None, offset: 96, ), ( name: Some("atom_arr"), - ty: 9, + ty: 10, binding: None, offset: 100, ), ( name: Some("arr"), - ty: 11, + ty: 12, binding: None, offset: 144, ), ( name: Some("data"), - ty: 12, + ty: 13, binding: None, offset: 160, ), @@ -196,7 +203,7 @@ members: [ ( name: Some("m"), - ty: 14, + ty: 15, binding: None, offset: 0, ), @@ -228,7 +235,7 @@ ( name: None, inner: Array( - base: 17, + base: 18, size: Constant(2), stride: 32, ), @@ -239,7 +246,7 @@ members: [ ( name: Some("am"), - ty: 18, + ty: 19, binding: None, offset: 0, ), @@ -247,24 +254,17 @@ span: 64, ), ), - ( - name: None, - inner: Scalar(( - kind: Float, - width: 4, - )), - ), ( name: None, inner: Pointer( - base: 20, + base: 5, space: Function, ), ), ( name: None, inner: Array( - base: 20, + base: 5, size: Constant(10), stride: 4, ), @@ -342,7 +342,7 @@ group: 0, binding: 0, )), - ty: 13, + ty: 14, init: None, ), ( @@ -352,7 +352,7 @@ group: 0, binding: 1, )), - ty: 15, + ty: 16, init: None, ), ( @@ -364,7 +364,7 @@ group: 0, binding: 2, )), - ty: 16, + ty: 17, init: None, ), ( @@ -374,7 +374,7 @@ group: 0, binding: 3, )), - ty: 19, + ty: 20, init: None, ), ], @@ -414,7 +414,7 @@ ), ( name: Some("t"), - ty: 15, + ty: 16, init: Some(48), ), ], @@ -557,7 +557,7 @@ value: 45, ), Compose( - ty: 14, + ty: 15, components: [ 42, 44, @@ -565,7 +565,7 @@ ], ), Compose( - ty: 15, + ty: 16, components: [ 47, ], @@ -600,7 +600,7 @@ value: 58, ), Compose( - ty: 14, + ty: 15, components: [ 55, 57, @@ -900,7 +900,7 @@ ), ( name: Some("t"), - ty: 19, + ty: 20, init: Some(52), ), ], @@ -1063,9 +1063,9 @@ Load( pointer: 49, ), - ZeroValue(18), + ZeroValue(19), Compose( - ty: 19, + ty: 20, components: [ 51, ], @@ -1084,7 +1084,7 @@ base: 53, index: 0, ), - ZeroValue(18), + ZeroValue(19), AccessIndex( base: 53, index: 0, @@ -1114,7 +1114,7 @@ value: 67, ), Compose( - ty: 17, + ty: 18, components: [ 62, 64, @@ -1502,7 +1502,7 @@ ), ], result: Some(( - ty: 20, + ty: 5, binding: None, )), local_variables: [], @@ -1535,7 +1535,7 @@ ), ], result: Some(( - ty: 20, + ty: 5, binding: None, )), local_variables: [], @@ -1680,7 +1680,7 @@ local_variables: [ ( name: Some("foo"), - ty: 20, + ty: 5, init: Some(1), ), ( @@ -2017,7 +2017,7 @@ value: 13, ), Compose( - ty: 5, + ty: 6, components: [ 8, 10, @@ -2041,7 +2041,7 @@ value: 20, ), Compose( - ty: 11, + ty: 12, components: [ 19, 21, @@ -2062,7 +2062,7 @@ ), Literal(I32(1)), GlobalVariable(3), - ZeroValue(16), + ZeroValue(17), Literal(F32(0.0)), Splat( size: Quad, diff --git a/naga/tests/out/ir/access.ron b/naga/tests/out/ir/access.ron index fd9405f2d0..1b95742ff2 100644 --- a/naga/tests/out/ir/access.ron +++ b/naga/tests/out/ir/access.ron @@ -64,6 +64,13 @@ span: 8, ), ), + ( + name: None, + inner: Scalar(( + kind: Float, + width: 4, + )), + ), ( name: None, inner: Matrix( @@ -89,7 +96,7 @@ ( name: None, inner: Array( - base: 6, + base: 7, size: Constant(2), stride: 16, ), @@ -104,7 +111,7 @@ ( name: None, inner: Array( - base: 8, + base: 9, size: Constant(10), stride: 4, ), @@ -122,7 +129,7 @@ ( name: None, inner: Array( - base: 10, + base: 11, size: Constant(2), stride: 8, ), @@ -141,37 +148,37 @@ members: [ ( name: Some("_matrix"), - ty: 5, + ty: 6, binding: None, offset: 0, ), ( name: Some("matrix_array"), - ty: 7, + ty: 8, binding: None, offset: 64, ), ( name: Some("atom"), - ty: 8, + ty: 9, binding: None, offset: 96, ), ( name: Some("atom_arr"), - ty: 9, + ty: 10, binding: None, offset: 100, ), ( name: Some("arr"), - ty: 11, + ty: 12, binding: None, offset: 144, ), ( name: Some("data"), - ty: 12, + ty: 13, binding: None, offset: 160, ), @@ -196,7 +203,7 @@ members: [ ( name: Some("m"), - ty: 14, + ty: 15, binding: None, offset: 0, ), @@ -228,7 +235,7 @@ ( name: None, inner: Array( - base: 17, + base: 18, size: Constant(2), stride: 32, ), @@ -239,7 +246,7 @@ members: [ ( name: Some("am"), - ty: 18, + ty: 19, binding: None, offset: 0, ), @@ -247,24 +254,17 @@ span: 64, ), ), - ( - name: None, - inner: Scalar(( - kind: Float, - width: 4, - )), - ), ( name: None, inner: Pointer( - base: 20, + base: 5, space: Function, ), ), ( name: None, inner: Array( - base: 20, + base: 5, size: Constant(10), stride: 4, ), @@ -342,7 +342,7 @@ group: 0, binding: 0, )), - ty: 13, + ty: 14, init: None, ), ( @@ -352,7 +352,7 @@ group: 0, binding: 1, )), - ty: 15, + ty: 16, init: None, ), ( @@ -364,7 +364,7 @@ group: 0, binding: 2, )), - ty: 16, + ty: 17, init: None, ), ( @@ -374,7 +374,7 @@ group: 0, binding: 3, )), - ty: 19, + ty: 20, init: None, ), ], @@ -414,7 +414,7 @@ ), ( name: Some("t"), - ty: 15, + ty: 16, init: Some(48), ), ], @@ -557,7 +557,7 @@ value: 45, ), Compose( - ty: 14, + ty: 15, components: [ 42, 44, @@ -565,7 +565,7 @@ ], ), Compose( - ty: 15, + ty: 16, components: [ 47, ], @@ -600,7 +600,7 @@ value: 58, ), Compose( - ty: 14, + ty: 15, components: [ 55, 57, @@ -900,7 +900,7 @@ ), ( name: Some("t"), - ty: 19, + ty: 20, init: Some(52), ), ], @@ -1063,9 +1063,9 @@ Load( pointer: 49, ), - ZeroValue(18), + ZeroValue(19), Compose( - ty: 19, + ty: 20, components: [ 51, ], @@ -1084,7 +1084,7 @@ base: 53, index: 0, ), - ZeroValue(18), + ZeroValue(19), AccessIndex( base: 53, index: 0, @@ -1114,7 +1114,7 @@ value: 67, ), Compose( - ty: 17, + ty: 18, components: [ 62, 64, @@ -1502,7 +1502,7 @@ ), ], result: Some(( - ty: 20, + ty: 5, binding: None, )), local_variables: [], @@ -1535,7 +1535,7 @@ ), ], result: Some(( - ty: 20, + ty: 5, binding: None, )), local_variables: [], @@ -1680,7 +1680,7 @@ local_variables: [ ( name: Some("foo"), - ty: 20, + ty: 5, init: Some(1), ), ( @@ -2017,7 +2017,7 @@ value: 13, ), Compose( - ty: 5, + ty: 6, components: [ 8, 10, @@ -2041,7 +2041,7 @@ value: 20, ), Compose( - ty: 11, + ty: 12, components: [ 19, 21, @@ -2062,7 +2062,7 @@ ), Literal(I32(1)), GlobalVariable(3), - ZeroValue(16), + ZeroValue(17), Literal(F32(0.0)), Splat( size: Quad, diff --git a/naga/tests/out/ir/atomic_i_increment.compact.ron b/naga/tests/out/ir/atomic_i_increment.compact.ron index 58b01f5870..12a4692a3e 100644 --- a/naga/tests/out/ir/atomic_i_increment.compact.ron +++ b/naga/tests/out/ir/atomic_i_increment.compact.ron @@ -216,10 +216,6 @@ ), ], reject: [ - Emit(( - start: 13, - end: 14, - )), Atomic( pointer: 7, fun: Add, diff --git a/naga/tests/out/ir/atomic_i_increment.ron b/naga/tests/out/ir/atomic_i_increment.ron index 2c55289218..82fa975024 100644 --- a/naga/tests/out/ir/atomic_i_increment.ron +++ b/naga/tests/out/ir/atomic_i_increment.ron @@ -241,10 +241,6 @@ ), ], reject: [ - Emit(( - start: 14, - end: 15, - )), Atomic( pointer: 8, fun: Add, diff --git a/naga/tests/out/ir/const_assert.compact.ron b/naga/tests/out/ir/const_assert.compact.ron new file mode 100644 index 0000000000..9dce67b5f9 --- /dev/null +++ b/naga/tests/out/ir/const_assert.compact.ron @@ -0,0 +1,54 @@ +( + types: [ + ( + name: None, + inner: Scalar(( + kind: Sint, + width: 4, + )), + ), + ], + special_types: ( + ray_desc: None, + ray_intersection: None, + predeclared_types: {}, + ), + constants: [ + ( + name: Some("x"), + ty: 0, + init: 0, + ), + ( + name: Some("y"), + ty: 0, + init: 1, + ), + ], + overrides: [], + global_variables: [], + global_expressions: [ + Literal(I32(1)), + Literal(I32(2)), + ], + functions: [ + ( + name: Some("foo"), + arguments: [], + result: None, + local_variables: [], + expressions: [ + Literal(I32(1)), + ], + named_expressions: { + 0: "z", + }, + body: [ + Return( + value: None, + ), + ], + ), + ], + entry_points: [], +) \ No newline at end of file diff --git a/naga/tests/out/ir/const_assert.ron b/naga/tests/out/ir/const_assert.ron new file mode 100644 index 0000000000..9dce67b5f9 --- /dev/null +++ b/naga/tests/out/ir/const_assert.ron @@ -0,0 +1,54 @@ +( + types: [ + ( + name: None, + inner: Scalar(( + kind: Sint, + width: 4, + )), + ), + ], + special_types: ( + ray_desc: None, + ray_intersection: None, + predeclared_types: {}, + ), + constants: [ + ( + name: Some("x"), + ty: 0, + init: 0, + ), + ( + name: Some("y"), + ty: 0, + init: 1, + ), + ], + overrides: [], + global_variables: [], + global_expressions: [ + Literal(I32(1)), + Literal(I32(2)), + ], + functions: [ + ( + name: Some("foo"), + arguments: [], + result: None, + local_variables: [], + expressions: [ + Literal(I32(1)), + ], + named_expressions: { + 0: "z", + }, + body: [ + Return( + value: None, + ), + ], + ), + ], + entry_points: [], +) \ No newline at end of file diff --git a/naga/tests/out/ir/local-const.compact.ron b/naga/tests/out/ir/local-const.compact.ron new file mode 100644 index 0000000000..a9b9f32af8 --- /dev/null +++ b/naga/tests/out/ir/local-const.compact.ron @@ -0,0 +1,139 @@ +( + types: [ + ( + name: None, + inner: Scalar(( + kind: Sint, + width: 4, + )), + ), + ( + name: None, + inner: Scalar(( + kind: Uint, + width: 4, + )), + ), + ( + name: None, + inner: Scalar(( + kind: Float, + width: 4, + )), + ), + ( + name: None, + inner: Vector( + size: Tri, + scalar: ( + kind: Sint, + width: 4, + ), + ), + ), + ], + special_types: ( + ray_desc: None, + ray_intersection: None, + predeclared_types: {}, + ), + constants: [ + ( + name: Some("ga"), + ty: 0, + init: 0, + ), + ( + name: Some("gb"), + ty: 0, + init: 1, + ), + ( + name: Some("gc"), + ty: 1, + init: 2, + ), + ( + name: Some("gd"), + ty: 2, + init: 3, + ), + ( + name: Some("ge"), + ty: 3, + init: 4, + ), + ( + name: Some("gf"), + ty: 2, + init: 5, + ), + ], + overrides: [], + global_variables: [], + global_expressions: [ + Literal(I32(4)), + Literal(I32(4)), + Literal(U32(4)), + Literal(F32(4.0)), + Compose( + ty: 3, + components: [ + 0, + 0, + 0, + ], + ), + Literal(F32(2.0)), + ], + functions: [ + ( + name: Some("const_in_fn"), + arguments: [], + result: None, + local_variables: [], + expressions: [ + Literal(I32(4)), + Literal(I32(4)), + Literal(U32(4)), + Literal(F32(4.0)), + Compose( + ty: 3, + components: [ + 0, + 0, + 0, + ], + ), + Literal(F32(2.0)), + Constant(0), + Constant(1), + Constant(2), + Constant(3), + Constant(4), + Constant(5), + ], + named_expressions: { + 0: "a", + 1: "b", + 2: "c", + 3: "d", + 4: "e", + 5: "f", + 6: "ag", + 7: "bg", + 8: "cg", + 9: "dg", + 10: "eg", + 11: "fg", + }, + body: [ + Emit(( + start: 4, + end: 5, + )), + ], + ), + ], + entry_points: [], +) \ No newline at end of file diff --git a/naga/tests/out/ir/local-const.ron b/naga/tests/out/ir/local-const.ron new file mode 100644 index 0000000000..a9b9f32af8 --- /dev/null +++ b/naga/tests/out/ir/local-const.ron @@ -0,0 +1,139 @@ +( + types: [ + ( + name: None, + inner: Scalar(( + kind: Sint, + width: 4, + )), + ), + ( + name: None, + inner: Scalar(( + kind: Uint, + width: 4, + )), + ), + ( + name: None, + inner: Scalar(( + kind: Float, + width: 4, + )), + ), + ( + name: None, + inner: Vector( + size: Tri, + scalar: ( + kind: Sint, + width: 4, + ), + ), + ), + ], + special_types: ( + ray_desc: None, + ray_intersection: None, + predeclared_types: {}, + ), + constants: [ + ( + name: Some("ga"), + ty: 0, + init: 0, + ), + ( + name: Some("gb"), + ty: 0, + init: 1, + ), + ( + name: Some("gc"), + ty: 1, + init: 2, + ), + ( + name: Some("gd"), + ty: 2, + init: 3, + ), + ( + name: Some("ge"), + ty: 3, + init: 4, + ), + ( + name: Some("gf"), + ty: 2, + init: 5, + ), + ], + overrides: [], + global_variables: [], + global_expressions: [ + Literal(I32(4)), + Literal(I32(4)), + Literal(U32(4)), + Literal(F32(4.0)), + Compose( + ty: 3, + components: [ + 0, + 0, + 0, + ], + ), + Literal(F32(2.0)), + ], + functions: [ + ( + name: Some("const_in_fn"), + arguments: [], + result: None, + local_variables: [], + expressions: [ + Literal(I32(4)), + Literal(I32(4)), + Literal(U32(4)), + Literal(F32(4.0)), + Compose( + ty: 3, + components: [ + 0, + 0, + 0, + ], + ), + Literal(F32(2.0)), + Constant(0), + Constant(1), + Constant(2), + Constant(3), + Constant(4), + Constant(5), + ], + named_expressions: { + 0: "a", + 1: "b", + 2: "c", + 3: "d", + 4: "e", + 5: "f", + 6: "ag", + 7: "bg", + 8: "cg", + 9: "dg", + 10: "eg", + 11: "fg", + }, + body: [ + Emit(( + start: 4, + end: 5, + )), + ], + ), + ], + entry_points: [], +) \ No newline at end of file diff --git a/naga/tests/out/msl/abstract-types-const.msl b/naga/tests/out/msl/abstract-types-const.msl index af4de25cc6..16a3e35b9a 100644 --- a/naga/tests/out/msl/abstract-types-const.msl +++ b/naga/tests/out/msl/abstract-types-const.msl @@ -4,7 +4,7 @@ using metal::uint; -struct type_5 { +struct type_7 { float inner[2]; }; struct S { @@ -32,12 +32,12 @@ constant metal::int2 ivis_ai = metal::int2(1); constant metal::uint2 ivus_ai = metal::uint2(1u); constant metal::float2 ivfs_ai = metal::float2(1.0); constant metal::float2 ivfs_af = metal::float2(1.0); -constant type_5 iafafaf = type_5 {1.0, 2.0}; -constant type_5 iafaiai = type_5 {1.0, 2.0}; -constant type_5 iafpafaf = type_5 {1.0, 2.0}; -constant type_5 iafpaiaf = type_5 {1.0, 2.0}; -constant type_5 iafpafai = type_5 {1.0, 2.0}; -constant type_5 xafpafaf = type_5 {1.0, 2.0}; +constant type_7 iafafaf = type_7 {1.0, 2.0}; +constant type_7 iafaiai = type_7 {1.0, 2.0}; +constant type_7 iafpafaf = type_7 {1.0, 2.0}; +constant type_7 iafpaiaf = type_7 {1.0, 2.0}; +constant type_7 iafpafai = type_7 {1.0, 2.0}; +constant type_7 xafpafaf = type_7 {1.0, 2.0}; constant S s_f_i_u = S {1.0, 1, 1u}; constant S s_f_iai = S {1.0, 1, 1u}; constant S s_fai_u = S {1.0, 1, 1u}; diff --git a/naga/tests/out/msl/abstract-types-var.msl b/naga/tests/out/msl/abstract-types-var.msl index 45096f8672..7d5623469b 100644 --- a/naga/tests/out/msl/abstract-types-var.msl +++ b/naga/tests/out/msl/abstract-types-var.msl @@ -4,10 +4,10 @@ using metal::uint; -struct type_5 { +struct type_7 { float inner[2]; }; -struct type_7 { +struct type_8 { int inner[2]; }; @@ -35,17 +35,17 @@ void all_constant_arguments( metal::uint2 xvus_ai = metal::uint2(1u); metal::float2 xvfs_ai = metal::float2(1.0); metal::float2 xvfs_af = metal::float2(1.0); - type_5 xafafaf = type_5 {1.0, 2.0}; - type_5 xaf_faf = type_5 {1.0, 2.0}; - type_5 xafaf_f = type_5 {1.0, 2.0}; - type_5 xafaiai = type_5 {1.0, 2.0}; - type_7 xai_iai = type_7 {1, 2}; - type_7 xaiai_i = type_7 {1, 2}; - type_7 xaipaiai = type_7 {1, 2}; - type_5 xafpaiai = type_5 {1.0, 2.0}; - type_5 xafpaiaf = type_5 {1.0, 2.0}; - type_5 xafpafai = type_5 {1.0, 2.0}; - type_5 xafpafaf = type_5 {1.0, 2.0}; + type_7 xafafaf = type_7 {1.0, 2.0}; + type_7 xaf_faf = type_7 {1.0, 2.0}; + type_7 xafaf_f = type_7 {1.0, 2.0}; + type_7 xafaiai = type_7 {1.0, 2.0}; + type_8 xai_iai = type_8 {1, 2}; + type_8 xaiai_i = type_8 {1, 2}; + type_8 xaipaiai = type_8 {1, 2}; + type_7 xafpaiai = type_7 {1.0, 2.0}; + type_7 xafpaiaf = type_7 {1.0, 2.0}; + type_7 xafpafai = type_7 {1.0, 2.0}; + type_7 xafpafaf = type_7 {1.0, 2.0}; } void mixed_constant_and_runtime_arguments( @@ -61,18 +61,18 @@ void mixed_constant_and_runtime_arguments( metal::float2x2 xmfpai_faiai_1 = {}; metal::float2x2 xmfpaiai_fai_1 = {}; metal::float2x2 xmfpaiaiai_f_1 = {}; - type_5 xaf_faf_1 = {}; - type_5 xafaf_f_1 = {}; - type_5 xaf_fai = {}; - type_5 xafai_f = {}; - type_7 xai_iai_1 = {}; - type_7 xaiai_i_1 = {}; - type_5 xafp_faf = {}; - type_5 xafpaf_f = {}; - type_5 xafp_fai = {}; - type_5 xafpai_f = {}; - type_7 xaip_iai = {}; - type_7 xaipai_i = {}; + type_7 xaf_faf_1 = {}; + type_7 xafaf_f_1 = {}; + type_7 xaf_fai = {}; + type_7 xafai_f = {}; + type_8 xai_iai_1 = {}; + type_8 xaiai_i_1 = {}; + type_7 xafp_faf = {}; + type_7 xafpaf_f = {}; + type_7 xafp_fai = {}; + type_7 xafpai_f = {}; + type_8 xaip_iai = {}; + type_8 xaipai_i = {}; uint _e3 = u; xvupuai_1 = metal::uint2(_e3, 43u); uint _e7 = u; @@ -90,28 +90,28 @@ void mixed_constant_and_runtime_arguments( float _e43 = f; xmfpaiaiai_f_1 = metal::float2x2(metal::float2(1.0, 2.0), metal::float2(3.0, _e43)); float _e51 = f; - xaf_faf_1 = type_5 {_e51, 2.0}; + xaf_faf_1 = type_7 {_e51, 2.0}; float _e55 = f; - xafaf_f_1 = type_5 {1.0, _e55}; + xafaf_f_1 = type_7 {1.0, _e55}; float _e59 = f; - xaf_fai = type_5 {_e59, 2.0}; + xaf_fai = type_7 {_e59, 2.0}; float _e63 = f; - xafai_f = type_5 {1.0, _e63}; + xafai_f = type_7 {1.0, _e63}; int _e67 = i; - xai_iai_1 = type_7 {_e67, 2}; + xai_iai_1 = type_8 {_e67, 2}; int _e71 = i; - xaiai_i_1 = type_7 {1, _e71}; + xaiai_i_1 = type_8 {1, _e71}; float _e75 = f; - xafp_faf = type_5 {_e75, 2.0}; + xafp_faf = type_7 {_e75, 2.0}; float _e79 = f; - xafpaf_f = type_5 {1.0, _e79}; + xafpaf_f = type_7 {1.0, _e79}; float _e83 = f; - xafp_fai = type_5 {_e83, 2.0}; + xafp_fai = type_7 {_e83, 2.0}; float _e87 = f; - xafpai_f = type_5 {1.0, _e87}; + xafpai_f = type_7 {1.0, _e87}; int _e91 = i; - xaip_iai = type_7 {_e91, 2}; + xaip_iai = type_8 {_e91, 2}; int _e95 = i; - xaipai_i = type_7 {1, _e95}; + xaipai_i = type_8 {1, _e95}; return; } diff --git a/naga/tests/out/msl/access.msl b/naga/tests/out/msl/access.msl index 908535ea31..65dba4910e 100644 --- a/naga/tests/out/msl/access.msl +++ b/naga/tests/out/msl/access.msl @@ -17,33 +17,33 @@ struct GlobalConst { struct AlignedWrapper { int value; }; -struct type_5 { +struct type_6 { metal::float2x2 inner[2]; }; -struct type_7 { +struct type_8 { metal::atomic_int inner[10]; }; -struct type_9 { +struct type_10 { metal::uint2 inner[2]; }; -typedef AlignedWrapper type_10[1]; +typedef AlignedWrapper type_11[1]; struct Bar { metal::float4x3 _matrix; - type_5 matrix_array; + type_6 matrix_array; metal::atomic_int atom; - type_7 atom_arr; + type_8 atom_arr; char _pad4[4]; - type_9 arr; - type_10 data; + type_10 arr; + type_11 data; }; struct Baz { metal::float3x2 m; }; -struct type_14 { +struct type_15 { metal::float4x2 inner[2]; }; struct MatCx2InArray { - type_14 am; + type_15 am; }; struct type_17 { float inner[10]; @@ -98,10 +98,10 @@ void test_matrix_within_array_within_struct_accesses( constant MatCx2InArray& nested_mat_cx2_ ) { int idx_1 = 1; - MatCx2InArray t_1 = MatCx2InArray {type_14 {}}; + MatCx2InArray t_1 = MatCx2InArray {type_15 {}}; int _e3 = idx_1; idx_1 = _e3 - 1; - type_14 l0_1 = nested_mat_cx2_.am; + type_15 l0_1 = nested_mat_cx2_.am; metal::float4x2 l1_1 = nested_mat_cx2_.am.inner[0]; metal::float2 l2_1 = nested_mat_cx2_.am.inner[0][0]; int _e20 = idx_1; @@ -116,7 +116,7 @@ void test_matrix_within_array_within_struct_accesses( float l7_ = nested_mat_cx2_.am.inner[0][_e46][_e48]; int _e55 = idx_1; idx_1 = _e55 + 1; - t_1.am = type_14 {}; + t_1.am = type_15 {}; t_1.am.inner[0] = metal::float4x2(metal::float2(8.0), metal::float2(7.0), metal::float2(6.0), metal::float2(5.0)); t_1.am.inner[0][0] = metal::float2(9.0); int _e77 = idx_1; @@ -179,7 +179,7 @@ vertex foo_vertOutput foo_vert( test_matrix_within_struct_accesses(baz); test_matrix_within_array_within_struct_accesses(nested_mat_cx2_); metal::float4x3 _matrix = bar._matrix; - type_9 arr_1 = bar.arr; + type_10 arr_1 = bar.arr; float b = bar._matrix[3u].x; int a_1 = bar.data[(1 + (_buffer_sizes.size1 - 160 - 8) / 8) - 2u].value; metal::int2 c = qux; @@ -202,7 +202,7 @@ fragment foo_fragOutput foo_frag( ) { bar._matrix[1].z = 1.0; bar._matrix = metal::float4x3(metal::float3(0.0), metal::float3(1.0), metal::float3(2.0), metal::float3(3.0)); - bar.arr = type_9 {metal::uint2(0u), metal::uint2(1u)}; + bar.arr = type_10 {metal::uint2(0u), metal::uint2(1u)}; bar.data[1].value = 1; qux = metal::int2 {}; return foo_fragOutput { metal::float4(0.0) }; diff --git a/naga/tests/out/msl/boids.msl b/naga/tests/out/msl/boids.msl index ce1ccc7cc2..0dd520ac74 100644 --- a/naga/tests/out/msl/boids.msl +++ b/naga/tests/out/msl/boids.msl @@ -55,8 +55,9 @@ kernel void main_( vPos = _e8; metal::float2 _e14 = particlesSrc.particles[index].vel; vVel = _e14; +#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop) bool loop_init = true; - while(true) { + LOOP_IS_REACHABLE while(true) { if (!loop_init) { uint _e91 = i; i = _e91 + 1u; diff --git a/naga/tests/out/msl/break-if.msl b/naga/tests/out/msl/break-if.msl index 8c0d9343b9..3684f7222c 100644 --- a/naga/tests/out/msl/break-if.msl +++ b/naga/tests/out/msl/break-if.msl @@ -7,8 +7,9 @@ using metal::uint; void breakIfEmpty( ) { +#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop) bool loop_init = true; - while(true) { + LOOP_IS_REACHABLE while(true) { if (!loop_init) { if (true) { break; @@ -25,7 +26,7 @@ void breakIfEmptyBody( bool b = {}; bool c = {}; bool loop_init_1 = true; - while(true) { + LOOP_IS_REACHABLE while(true) { if (!loop_init_1) { b = a; bool _e2 = b; @@ -46,7 +47,7 @@ void breakIf( bool d = {}; bool e = {}; bool loop_init_2 = true; - while(true) { + LOOP_IS_REACHABLE while(true) { if (!loop_init_2) { bool _e5 = e; if (a_1 == e) { @@ -65,7 +66,7 @@ void breakIfSeparateVariable( ) { uint counter = 0u; bool loop_init_3 = true; - while(true) { + LOOP_IS_REACHABLE while(true) { if (!loop_init_3) { uint _e5 = counter; if (counter == 5u) { diff --git a/naga/tests/out/msl/collatz.msl b/naga/tests/out/msl/collatz.msl index e283741459..1ae910de6f 100644 --- a/naga/tests/out/msl/collatz.msl +++ b/naga/tests/out/msl/collatz.msl @@ -19,7 +19,8 @@ uint collatz_iterations( uint n = {}; uint i = 0u; n = n_base; - while(true) { +#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop) + LOOP_IS_REACHABLE while(true) { uint _e4 = n; if (_e4 > 1u) { } else { diff --git a/naga/tests/out/msl/constructors.msl b/naga/tests/out/msl/constructors.msl index 6733568a92..d4dc5c5292 100644 --- a/naga/tests/out/msl/constructors.msl +++ b/naga/tests/out/msl/constructors.msl @@ -8,7 +8,7 @@ struct Foo { metal::float4 a; int b; }; -struct type_5 { +struct type_6 { metal::float2x2 inner[1]; }; struct type_10 { @@ -19,7 +19,7 @@ struct type_11 { }; constant metal::float3 const2_ = metal::float3(0.0, 1.0, 2.0); constant metal::float2x2 const3_ = metal::float2x2(metal::float2(0.0, 1.0), metal::float2(2.0, 3.0)); -constant type_5 const4_ = type_5 {metal::float2x2(metal::float2(0.0, 1.0), metal::float2(2.0, 3.0))}; +constant type_6 const4_ = type_6 {metal::float2x2(metal::float2(0.0, 1.0), metal::float2(2.0, 3.0))}; constant bool cz0_ = bool {}; constant int cz1_ = int {}; constant uint cz2_ = uint {}; diff --git a/naga/tests/out/msl/control-flow.msl b/naga/tests/out/msl/control-flow.msl index 11771693aa..dbf75163aa 100644 --- a/naga/tests/out/msl/control-flow.msl +++ b/naga/tests/out/msl/control-flow.msl @@ -31,7 +31,8 @@ void switch_case_break( void loop_switch_continue( int x ) { - while(true) { +#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop) + LOOP_IS_REACHABLE while(true) { switch(x) { case 1: { continue; @@ -49,7 +50,7 @@ void loop_switch_continue_nesting( int y, int z ) { - while(true) { + LOOP_IS_REACHABLE while(true) { switch(x_1) { case 1: { continue; @@ -60,7 +61,7 @@ void loop_switch_continue_nesting( continue; } default: { - while(true) { + LOOP_IS_REACHABLE while(true) { switch(z) { case 1: { continue; @@ -85,7 +86,7 @@ void loop_switch_continue_nesting( } } } - while(true) { + LOOP_IS_REACHABLE while(true) { switch(y) { case 1: default: { @@ -108,7 +109,7 @@ void loop_switch_omit_continue_variable_checks( int w ) { int pos_1 = 0; - while(true) { + LOOP_IS_REACHABLE while(true) { switch(x_2) { case 1: { pos_1 = 1; @@ -119,7 +120,7 @@ void loop_switch_omit_continue_variable_checks( } } } - while(true) { + LOOP_IS_REACHABLE while(true) { switch(x_2) { case 1: { break; diff --git a/naga/tests/out/msl/cross.msl b/naga/tests/out/msl/cross.msl new file mode 100644 index 0000000000..70095cd6e9 --- /dev/null +++ b/naga/tests/out/msl/cross.msl @@ -0,0 +1,11 @@ +// language: metal1.0 +#include +#include + +using metal::uint; + + +kernel void main_( +) { + metal::float3 a = metal::cross(metal::float3(0.0, 1.0, 2.0), metal::float3(0.0, 1.0, 2.0)); +} diff --git a/naga/tests/out/msl/do-while.msl b/naga/tests/out/msl/do-while.msl index c1b4d08b0e..b093da1dc5 100644 --- a/naga/tests/out/msl/do-while.msl +++ b/naga/tests/out/msl/do-while.msl @@ -8,8 +8,9 @@ using metal::uint; void fb1_( thread bool& cond ) { +#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop) bool loop_init = true; - while(true) { + LOOP_IS_REACHABLE while(true) { if (!loop_init) { bool _e1 = cond; if (!(cond)) { diff --git a/naga/tests/out/msl/interpolate.msl b/naga/tests/out/msl/interpolate.msl index 616291253f..c19005753f 100644 --- a/naga/tests/out/msl/interpolate.msl +++ b/naga/tests/out/msl/interpolate.msl @@ -7,54 +7,71 @@ using metal::uint; struct FragmentInput { metal::float4 position; uint _flat; + uint flat_first; + uint flat_either; float _linear; metal::float2 linear_centroid; + char _pad6[8]; metal::float3 linear_sample; + metal::float3 linear_center; metal::float4 perspective; float perspective_centroid; float perspective_sample; + float perspective_center; }; struct vert_mainOutput { metal::float4 position [[position]]; uint _flat [[user(loc0), flat]]; - float _linear [[user(loc1), center_no_perspective]]; - metal::float2 linear_centroid [[user(loc2), centroid_no_perspective]]; - metal::float3 linear_sample [[user(loc3), sample_no_perspective]]; - metal::float4 perspective [[user(loc4), center_perspective]]; - float perspective_centroid [[user(loc5), centroid_perspective]]; - float perspective_sample [[user(loc6), sample_perspective]]; + uint flat_first [[user(loc1), flat]]; + uint flat_either [[user(loc2), flat]]; + float _linear [[user(loc3), center_no_perspective]]; + metal::float2 linear_centroid [[user(loc4), centroid_no_perspective]]; + metal::float3 linear_sample [[user(loc6), sample_no_perspective]]; + metal::float3 linear_center [[user(loc7), center_no_perspective]]; + metal::float4 perspective [[user(loc8), center_perspective]]; + float perspective_centroid [[user(loc9), centroid_perspective]]; + float perspective_sample [[user(loc10), sample_perspective]]; + float perspective_center [[user(loc11), center_perspective]]; }; vertex vert_mainOutput vert_main( ) { FragmentInput out = {}; out.position = metal::float4(2.0, 4.0, 5.0, 6.0); out._flat = 8u; + out.flat_first = 9u; + out.flat_either = 10u; out._linear = 27.0; out.linear_centroid = metal::float2(64.0, 125.0); out.linear_sample = metal::float3(216.0, 343.0, 512.0); + out.linear_center = metal::float3(255.0, 511.0, 1024.0); out.perspective = metal::float4(729.0, 1000.0, 1331.0, 1728.0); out.perspective_centroid = 2197.0; out.perspective_sample = 2744.0; - FragmentInput _e30 = out; - const auto _tmp = _e30; - return vert_mainOutput { _tmp.position, _tmp._flat, _tmp._linear, _tmp.linear_centroid, _tmp.linear_sample, _tmp.perspective, _tmp.perspective_centroid, _tmp.perspective_sample }; + out.perspective_center = 2812.0; + FragmentInput _e41 = out; + const auto _tmp = _e41; + return vert_mainOutput { _tmp.position, _tmp._flat, _tmp.flat_first, _tmp.flat_either, _tmp._linear, _tmp.linear_centroid, _tmp.linear_sample, _tmp.linear_center, _tmp.perspective, _tmp.perspective_centroid, _tmp.perspective_sample, _tmp.perspective_center }; } struct frag_mainInput { uint _flat [[user(loc0), flat]]; - float _linear [[user(loc1), center_no_perspective]]; - metal::float2 linear_centroid [[user(loc2), centroid_no_perspective]]; - metal::float3 linear_sample [[user(loc3), sample_no_perspective]]; - metal::float4 perspective [[user(loc4), center_perspective]]; - float perspective_centroid [[user(loc5), centroid_perspective]]; - float perspective_sample [[user(loc6), sample_perspective]]; + uint flat_first [[user(loc1), flat]]; + uint flat_either [[user(loc2), flat]]; + float _linear [[user(loc3), center_no_perspective]]; + metal::float2 linear_centroid [[user(loc4), centroid_no_perspective]]; + metal::float3 linear_sample [[user(loc6), sample_no_perspective]]; + metal::float3 linear_center [[user(loc7), center_no_perspective]]; + metal::float4 perspective [[user(loc8), center_perspective]]; + float perspective_centroid [[user(loc9), centroid_perspective]]; + float perspective_sample [[user(loc10), sample_perspective]]; + float perspective_center [[user(loc11), center_perspective]]; }; fragment void frag_main( frag_mainInput varyings_1 [[stage_in]] , metal::float4 position [[position]] ) { - const FragmentInput val = { position, varyings_1._flat, varyings_1._linear, varyings_1.linear_centroid, varyings_1.linear_sample, varyings_1.perspective, varyings_1.perspective_centroid, varyings_1.perspective_sample }; + const FragmentInput val = { position, varyings_1._flat, varyings_1.flat_first, varyings_1.flat_either, varyings_1._linear, varyings_1.linear_centroid, {}, varyings_1.linear_sample, varyings_1.linear_center, varyings_1.perspective, varyings_1.perspective_centroid, varyings_1.perspective_sample, varyings_1.perspective_center }; return; } diff --git a/naga/tests/out/msl/interpolate_compat.msl b/naga/tests/out/msl/interpolate_compat.msl new file mode 100644 index 0000000000..e386c07db0 --- /dev/null +++ b/naga/tests/out/msl/interpolate_compat.msl @@ -0,0 +1,74 @@ +// language: metal1.0 +#include +#include + +using metal::uint; + +struct FragmentInput { + metal::float4 position; + uint _flat; + uint flat_either; + float _linear; + char _pad4[4]; + metal::float2 linear_centroid; + char _pad5[8]; + metal::float3 linear_sample; + metal::float3 linear_center; + metal::float4 perspective; + float perspective_centroid; + float perspective_sample; + float perspective_center; +}; + +struct vert_mainOutput { + metal::float4 position [[position]]; + uint _flat [[user(loc0), flat]]; + uint flat_either [[user(loc2), flat]]; + float _linear [[user(loc3), center_no_perspective]]; + metal::float2 linear_centroid [[user(loc4), centroid_no_perspective]]; + metal::float3 linear_sample [[user(loc6), sample_no_perspective]]; + metal::float3 linear_center [[user(loc7), center_no_perspective]]; + metal::float4 perspective [[user(loc8), center_perspective]]; + float perspective_centroid [[user(loc9), centroid_perspective]]; + float perspective_sample [[user(loc10), sample_perspective]]; + float perspective_center [[user(loc11), center_perspective]]; +}; +vertex vert_mainOutput vert_main( +) { + FragmentInput out = {}; + out.position = metal::float4(2.0, 4.0, 5.0, 6.0); + out._flat = 8u; + out.flat_either = 10u; + out._linear = 27.0; + out.linear_centroid = metal::float2(64.0, 125.0); + out.linear_sample = metal::float3(216.0, 343.0, 512.0); + out.linear_center = metal::float3(255.0, 511.0, 1024.0); + out.perspective = metal::float4(729.0, 1000.0, 1331.0, 1728.0); + out.perspective_centroid = 2197.0; + out.perspective_sample = 2744.0; + out.perspective_center = 2812.0; + FragmentInput _e39 = out; + const auto _tmp = _e39; + return vert_mainOutput { _tmp.position, _tmp._flat, _tmp.flat_either, _tmp._linear, _tmp.linear_centroid, _tmp.linear_sample, _tmp.linear_center, _tmp.perspective, _tmp.perspective_centroid, _tmp.perspective_sample, _tmp.perspective_center }; +} + + +struct frag_mainInput { + uint _flat [[user(loc0), flat]]; + uint flat_either [[user(loc2), flat]]; + float _linear [[user(loc3), center_no_perspective]]; + metal::float2 linear_centroid [[user(loc4), centroid_no_perspective]]; + metal::float3 linear_sample [[user(loc6), sample_no_perspective]]; + metal::float3 linear_center [[user(loc7), center_no_perspective]]; + metal::float4 perspective [[user(loc8), center_perspective]]; + float perspective_centroid [[user(loc9), centroid_perspective]]; + float perspective_sample [[user(loc10), sample_perspective]]; + float perspective_center [[user(loc11), center_perspective]]; +}; +fragment void frag_main( + frag_mainInput varyings_1 [[stage_in]] +, metal::float4 position [[position]] +) { + const FragmentInput val = { position, varyings_1._flat, varyings_1.flat_either, varyings_1._linear, {}, varyings_1.linear_centroid, {}, varyings_1.linear_sample, varyings_1.linear_center, varyings_1.perspective, varyings_1.perspective_centroid, varyings_1.perspective_sample, varyings_1.perspective_center }; + return; +} diff --git a/naga/tests/out/msl/overrides-ray-query.msl b/naga/tests/out/msl/overrides-ray-query.msl index 3a508b6f61..f2ad45c985 100644 --- a/naga/tests/out/msl/overrides-ray-query.msl +++ b/naga/tests/out/msl/overrides-ray-query.msl @@ -33,7 +33,8 @@ kernel void main_( rq.intersector.force_opacity((desc.flags & 1) != 0 ? metal::raytracing::forced_opacity::opaque : (desc.flags & 2) != 0 ? metal::raytracing::forced_opacity::non_opaque : metal::raytracing::forced_opacity::none); rq.intersector.accept_any_intersection((desc.flags & 4) != 0); rq.intersection = rq.intersector.intersect(metal::raytracing::ray(desc.origin, desc.dir, desc.tmin, desc.tmax), acc_struct, desc.cull_mask); rq.ready = true; - while(true) { +#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop) + LOOP_IS_REACHABLE while(true) { bool _e31 = rq.ready; rq.ready = false; if (_e31) { diff --git a/naga/tests/out/msl/policy-mix.msl b/naga/tests/out/msl/policy-mix.msl index 24a40179a8..468b6f507a 100644 --- a/naga/tests/out/msl/policy-mix.msl +++ b/naga/tests/out/msl/policy-mix.msl @@ -10,17 +10,17 @@ struct DefaultConstructible { } }; -struct type_1 { +struct type_2 { metal::float4 inner[10]; }; struct InStorage { - type_1 a; + type_2 a; }; -struct type_2 { +struct type_3 { metal::float4 inner[20]; }; struct InUniform { - type_2 a; + type_3 a; }; struct type_5 { float inner[30]; diff --git a/naga/tests/out/msl/ray-query.msl b/naga/tests/out/msl/ray-query.msl index fbdaef5484..129ad108a9 100644 --- a/naga/tests/out/msl/ray-query.msl +++ b/naga/tests/out/msl/ray-query.msl @@ -53,7 +53,8 @@ RayIntersection query_loop( rq.intersector.force_opacity((_e8.flags & 1) != 0 ? metal::raytracing::forced_opacity::opaque : (_e8.flags & 2) != 0 ? metal::raytracing::forced_opacity::non_opaque : metal::raytracing::forced_opacity::none); rq.intersector.accept_any_intersection((_e8.flags & 4) != 0); rq.intersection = rq.intersector.intersect(metal::raytracing::ray(_e8.origin, _e8.dir, _e8.tmin, _e8.tmax), acs, _e8.cull_mask); rq.ready = true; - while(true) { +#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop) + LOOP_IS_REACHABLE while(true) { bool _e9 = rq.ready; rq.ready = false; if (_e9) { diff --git a/naga/tests/out/msl/shadow.msl b/naga/tests/out/msl/shadow.msl index 2443f002f2..f8aeef9d45 100644 --- a/naga/tests/out/msl/shadow.msl +++ b/naga/tests/out/msl/shadow.msl @@ -26,8 +26,8 @@ struct Light { metal::float4 pos; metal::float4 color; }; -typedef Light type_6[1]; -struct type_7 { +typedef Light type_8[1]; +struct type_9 { Light inner[10]; }; constant metal::float3 c_ambient = metal::float3(0.05, 0.05, 0.05); @@ -91,7 +91,7 @@ fragment fs_mainOutput fs_main( , metal::float4 proj_position [[position]] , constant Globals& u_globals [[user(fake0)]] , constant Entity& u_entity [[user(fake0)]] -, device type_6 const& s_lights [[user(fake0)]] +, device type_8 const& s_lights [[user(fake0)]] , metal::depth2d_array t_shadow [[user(fake0)]] , metal::sampler sampler_shadow [[user(fake0)]] , constant _mslBufferSizes& _buffer_sizes [[user(fake0)]] @@ -100,8 +100,9 @@ fragment fs_mainOutput fs_main( metal::float3 color = c_ambient; uint i = 0u; metal::float3 normal_1 = metal::normalize(in.world_normal); +#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop) bool loop_init = true; - while(true) { + LOOP_IS_REACHABLE while(true) { if (!loop_init) { uint _e40 = i; i = _e40 + 1u; @@ -142,7 +143,7 @@ fragment fs_main_without_storageOutput fs_main_without_storage( , metal::float4 proj_position_1 [[position]] , constant Globals& u_globals [[user(fake0)]] , constant Entity& u_entity [[user(fake0)]] -, constant type_7& u_lights [[user(fake0)]] +, constant type_9& u_lights [[user(fake0)]] , metal::depth2d_array t_shadow [[user(fake0)]] , metal::sampler sampler_shadow [[user(fake0)]] ) { @@ -151,7 +152,7 @@ fragment fs_main_without_storageOutput fs_main_without_storage( uint i_1 = 0u; metal::float3 normal_2 = metal::normalize(in_1.world_normal); bool loop_init_1 = true; - while(true) { + LOOP_IS_REACHABLE while(true) { if (!loop_init_1) { uint _e40 = i_1; i_1 = _e40 + 1u; diff --git a/naga/tests/out/spv/abstract-types-const.spvasm b/naga/tests/out/spv/abstract-types-const.spvasm index 207a04f564..edebb600ac 100644 --- a/naga/tests/out/spv/abstract-types-const.spvasm +++ b/naga/tests/out/spv/abstract-types-const.spvasm @@ -11,36 +11,36 @@ OpMemberDecorate %12 0 Offset 0 OpMemberDecorate %12 1 Offset 4 OpMemberDecorate %12 2 Offset 8 %2 = OpTypeVoid -%4 = OpTypeInt 32 0 -%3 = OpTypeVector %4 2 -%6 = OpTypeFloat 32 -%5 = OpTypeVector %6 2 -%7 = OpTypeMatrix %5 2 +%3 = OpTypeInt 32 0 +%4 = OpTypeVector %3 2 +%5 = OpTypeFloat 32 +%6 = OpTypeVector %5 2 +%7 = OpTypeMatrix %6 2 %9 = OpTypeInt 32 1 %8 = OpTypeVector %9 2 -%11 = OpConstant %4 2 -%10 = OpTypeArray %6 %11 -%12 = OpTypeStruct %6 %9 %4 -%13 = OpTypeVector %6 3 -%14 = OpConstant %4 42 -%15 = OpConstant %4 43 -%16 = OpConstantComposite %3 %14 %15 -%17 = OpConstant %6 44.0 -%18 = OpConstant %6 45.0 -%19 = OpConstantComposite %5 %17 %18 -%20 = OpConstant %6 1.0 -%21 = OpConstant %6 2.0 -%22 = OpConstantComposite %5 %20 %21 -%23 = OpConstant %6 3.0 -%24 = OpConstant %6 4.0 -%25 = OpConstantComposite %5 %23 %24 +%11 = OpConstant %3 2 +%10 = OpTypeArray %5 %11 +%12 = OpTypeStruct %5 %9 %3 +%13 = OpTypeVector %5 3 +%14 = OpConstant %3 42 +%15 = OpConstant %3 43 +%16 = OpConstantComposite %4 %14 %15 +%17 = OpConstant %5 44.0 +%18 = OpConstant %5 45.0 +%19 = OpConstantComposite %6 %17 %18 +%20 = OpConstant %5 1.0 +%21 = OpConstant %5 2.0 +%22 = OpConstantComposite %6 %20 %21 +%23 = OpConstant %5 3.0 +%24 = OpConstant %5 4.0 +%25 = OpConstantComposite %6 %23 %24 %26 = OpConstantComposite %7 %22 %25 %27 = OpConstant %9 1 %28 = OpConstantComposite %8 %27 %27 -%29 = OpConstantComposite %5 %20 %20 -%30 = OpConstant %4 1 -%31 = OpConstantComposite %3 %30 %30 +%29 = OpConstantComposite %6 %20 %20 +%30 = OpConstant %3 1 +%31 = OpConstantComposite %4 %30 %30 %32 = OpConstantComposite %10 %20 %21 %33 = OpConstantComposite %12 %20 %27 %30 %34 = OpConstantComposite %13 %20 %21 %23 -%35 = OpConstantComposite %5 %21 %23 \ No newline at end of file +%35 = OpConstantComposite %6 %21 %23 \ No newline at end of file diff --git a/naga/tests/out/spv/abstract-types-var.spvasm b/naga/tests/out/spv/abstract-types-var.spvasm index 1b4b0664b4..59dba569cd 100644 --- a/naga/tests/out/spv/abstract-types-var.spvasm +++ b/naga/tests/out/spv/abstract-types-var.spvasm @@ -1,7 +1,7 @@ ; SPIR-V ; Version: 1.1 ; Generator: rspirv -; Bound: 209 +; Bound: 220 OpCapability Shader OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" @@ -9,48 +9,48 @@ OpMemoryModel Logical GLSL450 OpDecorate %10 ArrayStride 4 OpDecorate %12 ArrayStride 4 %2 = OpTypeVoid -%4 = OpTypeInt 32 1 -%3 = OpTypeVector %4 2 -%6 = OpTypeInt 32 0 -%5 = OpTypeVector %6 2 -%8 = OpTypeFloat 32 -%7 = OpTypeVector %8 2 -%9 = OpTypeMatrix %7 2 -%11 = OpConstant %6 2 -%10 = OpTypeArray %8 %11 -%12 = OpTypeArray %4 %11 -%13 = OpConstant %4 42 -%14 = OpConstant %4 43 -%15 = OpConstantComposite %3 %13 %14 -%16 = OpConstant %6 44 -%17 = OpConstant %6 45 -%18 = OpConstantComposite %5 %16 %17 -%19 = OpConstant %8 46.0 -%20 = OpConstant %8 47.0 -%21 = OpConstantComposite %7 %19 %20 -%22 = OpConstant %6 42 -%23 = OpConstant %6 43 -%24 = OpConstantComposite %5 %22 %23 -%25 = OpConstant %8 1.0 -%26 = OpConstant %8 2.0 -%27 = OpConstantComposite %7 %25 %26 -%28 = OpConstant %8 3.0 -%29 = OpConstant %8 4.0 -%30 = OpConstantComposite %7 %28 %29 +%3 = OpTypeInt 32 1 +%4 = OpTypeVector %3 2 +%5 = OpTypeInt 32 0 +%6 = OpTypeVector %5 2 +%7 = OpTypeFloat 32 +%8 = OpTypeVector %7 2 +%9 = OpTypeMatrix %8 2 +%11 = OpConstant %5 2 +%10 = OpTypeArray %7 %11 +%12 = OpTypeArray %3 %11 +%13 = OpConstant %3 42 +%14 = OpConstant %3 43 +%15 = OpConstantComposite %4 %13 %14 +%16 = OpConstant %5 44 +%17 = OpConstant %5 45 +%18 = OpConstantComposite %6 %16 %17 +%19 = OpConstant %7 46.0 +%20 = OpConstant %7 47.0 +%21 = OpConstantComposite %8 %19 %20 +%22 = OpConstant %5 42 +%23 = OpConstant %5 43 +%24 = OpConstantComposite %6 %22 %23 +%25 = OpConstant %7 1.0 +%26 = OpConstant %7 2.0 +%27 = OpConstantComposite %8 %25 %26 +%28 = OpConstant %7 3.0 +%29 = OpConstant %7 4.0 +%30 = OpConstantComposite %8 %28 %29 %31 = OpConstantComposite %9 %27 %30 -%32 = OpConstant %4 1 -%33 = OpConstantComposite %3 %32 %32 -%34 = OpConstantComposite %7 %25 %25 -%35 = OpConstant %6 1 -%36 = OpConstantComposite %5 %35 %35 +%32 = OpConstant %3 1 +%33 = OpConstantComposite %4 %32 %32 +%34 = OpConstantComposite %8 %25 %25 +%35 = OpConstant %5 1 +%36 = OpConstantComposite %6 %35 %35 %37 = OpConstantComposite %10 %25 %26 -%38 = OpConstant %4 2 +%38 = OpConstant %3 2 %39 = OpConstantComposite %12 %32 %38 -%41 = OpTypePointer Private %3 +%41 = OpTypePointer Private %4 %40 = OpVariable %41 Private %15 -%43 = OpTypePointer Private %5 +%43 = OpTypePointer Private %6 %42 = OpVariable %43 Private %18 -%45 = OpTypePointer Private %7 +%45 = OpTypePointer Private %8 %44 = OpVariable %45 Private %21 %46 = OpVariable %43 Private %24 %47 = OpVariable %43 Private %24 @@ -76,168 +76,179 @@ OpDecorate %12 ArrayStride 4 %67 = OpVariable %63 Private %37 %68 = OpVariable %63 Private %37 %69 = OpVariable %63 Private %37 -%72 = OpTypeFunction %2 -%74 = OpTypePointer Function %3 -%76 = OpTypePointer Function %5 -%78 = OpTypePointer Function %7 -%84 = OpTypePointer Function %9 -%100 = OpTypePointer Function %10 -%105 = OpTypePointer Function %12 -%116 = OpTypePointer Function %6 -%117 = OpConstantNull %6 -%119 = OpTypePointer Function %4 -%120 = OpConstantNull %4 -%122 = OpTypePointer Function %8 -%123 = OpConstantNull %8 -%125 = OpConstantNull %5 -%127 = OpConstantNull %5 -%129 = OpConstantNull %5 -%131 = OpConstantNull %5 -%133 = OpConstantNull %9 -%135 = OpConstantNull %9 -%137 = OpConstantNull %9 -%139 = OpConstantNull %9 -%141 = OpConstantNull %10 -%143 = OpConstantNull %10 -%145 = OpConstantNull %10 -%147 = OpConstantNull %10 -%149 = OpConstantNull %12 -%151 = OpConstantNull %12 -%153 = OpConstantNull %10 -%155 = OpConstantNull %10 -%157 = OpConstantNull %10 -%159 = OpConstantNull %10 -%161 = OpConstantNull %12 -%163 = OpConstantNull %12 -%71 = OpFunction %2 None %72 -%70 = OpLabel -%109 = OpVariable %100 Function %37 -%106 = OpVariable %105 Function %39 -%102 = OpVariable %100 Function %37 -%98 = OpVariable %78 Function %34 -%95 = OpVariable %74 Function %33 -%92 = OpVariable %84 Function %31 -%89 = OpVariable %84 Function %31 -%86 = OpVariable %84 Function %31 -%82 = OpVariable %76 Function %24 -%79 = OpVariable %76 Function %24 -%73 = OpVariable %74 Function %15 -%110 = OpVariable %100 Function %37 -%107 = OpVariable %105 Function %39 -%103 = OpVariable %100 Function %37 -%99 = OpVariable %100 Function %37 -%96 = OpVariable %76 Function %36 -%93 = OpVariable %74 Function %33 -%90 = OpVariable %84 Function %31 -%87 = OpVariable %84 Function %31 -%83 = OpVariable %84 Function %31 -%80 = OpVariable %76 Function %24 -%75 = OpVariable %76 Function %18 -%111 = OpVariable %100 Function %37 -%108 = OpVariable %100 Function %37 -%104 = OpVariable %105 Function %39 -%101 = OpVariable %100 Function %37 -%97 = OpVariable %78 Function %34 -%94 = OpVariable %78 Function %34 -%91 = OpVariable %84 Function %31 -%88 = OpVariable %84 Function %31 -%85 = OpVariable %84 Function %31 -%81 = OpVariable %76 Function %24 -%77 = OpVariable %78 Function %21 -OpBranch %112 -%112 = OpLabel +%70 = OpVariable %41 Private %33 +%71 = OpVariable %45 Private %34 +%72 = OpVariable %41 Private %33 +%73 = OpVariable %43 Private %36 +%74 = OpVariable %45 Private %34 +%75 = OpVariable %45 Private %34 +%76 = OpVariable %63 Private %37 +%77 = OpVariable %63 Private %37 +%78 = OpVariable %63 Private %37 +%79 = OpVariable %63 Private %37 +%80 = OpVariable %63 Private %37 +%83 = OpTypeFunction %2 +%85 = OpTypePointer Function %4 +%87 = OpTypePointer Function %6 +%89 = OpTypePointer Function %8 +%95 = OpTypePointer Function %9 +%111 = OpTypePointer Function %10 +%116 = OpTypePointer Function %12 +%127 = OpTypePointer Function %5 +%128 = OpConstantNull %5 +%130 = OpTypePointer Function %3 +%131 = OpConstantNull %3 +%133 = OpTypePointer Function %7 +%134 = OpConstantNull %7 +%136 = OpConstantNull %6 +%138 = OpConstantNull %6 +%140 = OpConstantNull %6 +%142 = OpConstantNull %6 +%144 = OpConstantNull %9 +%146 = OpConstantNull %9 +%148 = OpConstantNull %9 +%150 = OpConstantNull %9 +%152 = OpConstantNull %10 +%154 = OpConstantNull %10 +%156 = OpConstantNull %10 +%158 = OpConstantNull %10 +%160 = OpConstantNull %12 +%162 = OpConstantNull %12 +%164 = OpConstantNull %10 +%166 = OpConstantNull %10 +%168 = OpConstantNull %10 +%170 = OpConstantNull %10 +%172 = OpConstantNull %12 +%174 = OpConstantNull %12 +%82 = OpFunction %2 None %83 +%81 = OpLabel +%120 = OpVariable %111 Function %37 +%117 = OpVariable %116 Function %39 +%113 = OpVariable %111 Function %37 +%109 = OpVariable %89 Function %34 +%106 = OpVariable %85 Function %33 +%103 = OpVariable %95 Function %31 +%100 = OpVariable %95 Function %31 +%97 = OpVariable %95 Function %31 +%93 = OpVariable %87 Function %24 +%90 = OpVariable %87 Function %24 +%84 = OpVariable %85 Function %15 +%121 = OpVariable %111 Function %37 +%118 = OpVariable %116 Function %39 +%114 = OpVariable %111 Function %37 +%110 = OpVariable %111 Function %37 +%107 = OpVariable %87 Function %36 +%104 = OpVariable %85 Function %33 +%101 = OpVariable %95 Function %31 +%98 = OpVariable %95 Function %31 +%94 = OpVariable %95 Function %31 +%91 = OpVariable %87 Function %24 +%86 = OpVariable %87 Function %18 +%122 = OpVariable %111 Function %37 +%119 = OpVariable %111 Function %37 +%115 = OpVariable %116 Function %39 +%112 = OpVariable %111 Function %37 +%108 = OpVariable %89 Function %34 +%105 = OpVariable %89 Function %34 +%102 = OpVariable %95 Function %31 +%99 = OpVariable %95 Function %31 +%96 = OpVariable %95 Function %31 +%92 = OpVariable %87 Function %24 +%88 = OpVariable %89 Function %21 +OpBranch %123 +%123 = OpLabel OpReturn OpFunctionEnd -%114 = OpFunction %2 None %72 -%113 = OpLabel -%162 = OpVariable %105 Function %163 -%156 = OpVariable %100 Function %157 -%150 = OpVariable %105 Function %151 -%144 = OpVariable %100 Function %145 -%138 = OpVariable %84 Function %139 -%132 = OpVariable %84 Function %133 -%126 = OpVariable %76 Function %127 -%118 = OpVariable %119 Function %120 -%160 = OpVariable %105 Function %161 -%154 = OpVariable %100 Function %155 -%148 = OpVariable %105 Function %149 -%142 = OpVariable %100 Function %143 -%136 = OpVariable %84 Function %137 -%130 = OpVariable %76 Function %131 -%124 = OpVariable %76 Function %125 -%115 = OpVariable %116 Function %117 -%158 = OpVariable %100 Function %159 -%152 = OpVariable %100 Function %153 -%146 = OpVariable %100 Function %147 -%140 = OpVariable %100 Function %141 -%134 = OpVariable %84 Function %135 -%128 = OpVariable %76 Function %129 -%121 = OpVariable %122 Function %123 -OpBranch %164 -%164 = OpLabel -%165 = OpLoad %6 %115 -%166 = OpCompositeConstruct %5 %165 %23 -OpStore %124 %166 -%167 = OpLoad %6 %115 -%168 = OpCompositeConstruct %5 %22 %167 -OpStore %126 %168 -%169 = OpLoad %6 %115 -%170 = OpCompositeConstruct %5 %169 %23 -OpStore %128 %170 -%171 = OpLoad %6 %115 -%172 = OpCompositeConstruct %5 %22 %171 -OpStore %130 %172 -%173 = OpLoad %8 %121 -%174 = OpCompositeConstruct %7 %173 %26 -%175 = OpCompositeConstruct %9 %174 %30 -OpStore %132 %175 -%176 = OpLoad %8 %121 -%177 = OpCompositeConstruct %7 %25 %176 -%178 = OpCompositeConstruct %9 %177 %30 -OpStore %134 %178 -%179 = OpLoad %8 %121 -%180 = OpCompositeConstruct %7 %179 %29 -%181 = OpCompositeConstruct %9 %27 %180 -OpStore %136 %181 -%182 = OpLoad %8 %121 -%183 = OpCompositeConstruct %7 %28 %182 -%184 = OpCompositeConstruct %9 %27 %183 -OpStore %138 %184 -%185 = OpLoad %8 %121 -%186 = OpCompositeConstruct %10 %185 %26 -OpStore %140 %186 -%187 = OpLoad %8 %121 -%188 = OpCompositeConstruct %10 %25 %187 -OpStore %142 %188 -%189 = OpLoad %8 %121 -%190 = OpCompositeConstruct %10 %189 %26 -OpStore %144 %190 -%191 = OpLoad %8 %121 -%192 = OpCompositeConstruct %10 %25 %191 -OpStore %146 %192 -%193 = OpLoad %4 %118 -%194 = OpCompositeConstruct %12 %193 %38 -OpStore %148 %194 -%195 = OpLoad %4 %118 -%196 = OpCompositeConstruct %12 %32 %195 -OpStore %150 %196 -%197 = OpLoad %8 %121 -%198 = OpCompositeConstruct %10 %197 %26 -OpStore %152 %198 -%199 = OpLoad %8 %121 -%200 = OpCompositeConstruct %10 %25 %199 -OpStore %154 %200 -%201 = OpLoad %8 %121 -%202 = OpCompositeConstruct %10 %201 %26 -OpStore %156 %202 -%203 = OpLoad %8 %121 -%204 = OpCompositeConstruct %10 %25 %203 -OpStore %158 %204 -%205 = OpLoad %4 %118 -%206 = OpCompositeConstruct %12 %205 %38 -OpStore %160 %206 -%207 = OpLoad %4 %118 -%208 = OpCompositeConstruct %12 %32 %207 -OpStore %162 %208 +%125 = OpFunction %2 None %83 +%124 = OpLabel +%173 = OpVariable %116 Function %174 +%167 = OpVariable %111 Function %168 +%161 = OpVariable %116 Function %162 +%155 = OpVariable %111 Function %156 +%149 = OpVariable %95 Function %150 +%143 = OpVariable %95 Function %144 +%137 = OpVariable %87 Function %138 +%129 = OpVariable %130 Function %131 +%171 = OpVariable %116 Function %172 +%165 = OpVariable %111 Function %166 +%159 = OpVariable %116 Function %160 +%153 = OpVariable %111 Function %154 +%147 = OpVariable %95 Function %148 +%141 = OpVariable %87 Function %142 +%135 = OpVariable %87 Function %136 +%126 = OpVariable %127 Function %128 +%169 = OpVariable %111 Function %170 +%163 = OpVariable %111 Function %164 +%157 = OpVariable %111 Function %158 +%151 = OpVariable %111 Function %152 +%145 = OpVariable %95 Function %146 +%139 = OpVariable %87 Function %140 +%132 = OpVariable %133 Function %134 +OpBranch %175 +%175 = OpLabel +%176 = OpLoad %5 %126 +%177 = OpCompositeConstruct %6 %176 %23 +OpStore %135 %177 +%178 = OpLoad %5 %126 +%179 = OpCompositeConstruct %6 %22 %178 +OpStore %137 %179 +%180 = OpLoad %5 %126 +%181 = OpCompositeConstruct %6 %180 %23 +OpStore %139 %181 +%182 = OpLoad %5 %126 +%183 = OpCompositeConstruct %6 %22 %182 +OpStore %141 %183 +%184 = OpLoad %7 %132 +%185 = OpCompositeConstruct %8 %184 %26 +%186 = OpCompositeConstruct %9 %185 %30 +OpStore %143 %186 +%187 = OpLoad %7 %132 +%188 = OpCompositeConstruct %8 %25 %187 +%189 = OpCompositeConstruct %9 %188 %30 +OpStore %145 %189 +%190 = OpLoad %7 %132 +%191 = OpCompositeConstruct %8 %190 %29 +%192 = OpCompositeConstruct %9 %27 %191 +OpStore %147 %192 +%193 = OpLoad %7 %132 +%194 = OpCompositeConstruct %8 %28 %193 +%195 = OpCompositeConstruct %9 %27 %194 +OpStore %149 %195 +%196 = OpLoad %7 %132 +%197 = OpCompositeConstruct %10 %196 %26 +OpStore %151 %197 +%198 = OpLoad %7 %132 +%199 = OpCompositeConstruct %10 %25 %198 +OpStore %153 %199 +%200 = OpLoad %7 %132 +%201 = OpCompositeConstruct %10 %200 %26 +OpStore %155 %201 +%202 = OpLoad %7 %132 +%203 = OpCompositeConstruct %10 %25 %202 +OpStore %157 %203 +%204 = OpLoad %3 %129 +%205 = OpCompositeConstruct %12 %204 %38 +OpStore %159 %205 +%206 = OpLoad %3 %129 +%207 = OpCompositeConstruct %12 %32 %206 +OpStore %161 %207 +%208 = OpLoad %7 %132 +%209 = OpCompositeConstruct %10 %208 %26 +OpStore %163 %209 +%210 = OpLoad %7 %132 +%211 = OpCompositeConstruct %10 %25 %210 +OpStore %165 %211 +%212 = OpLoad %7 %132 +%213 = OpCompositeConstruct %10 %212 %26 +OpStore %167 %213 +%214 = OpLoad %7 %132 +%215 = OpCompositeConstruct %10 %25 %214 +OpStore %169 %215 +%216 = OpLoad %3 %129 +%217 = OpCompositeConstruct %12 %216 %38 +OpStore %171 %217 +%218 = OpLoad %3 %129 +%219 = OpCompositeConstruct %12 %32 %218 +OpStore %173 %219 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/access.spvasm b/naga/tests/out/spv/access.spvasm index 3446878c9a..ab0112870f 100644 --- a/naga/tests/out/spv/access.spvasm +++ b/naga/tests/out/spv/access.spvasm @@ -108,10 +108,10 @@ OpDecorate %272 Location 0 %5 = OpTypeInt 32 1 %6 = OpTypeStruct %3 %4 %5 %7 = OpTypeStruct %5 -%10 = OpTypeFloat 32 -%9 = OpTypeVector %10 3 -%8 = OpTypeMatrix %9 4 -%12 = OpTypeVector %10 2 +%8 = OpTypeFloat 32 +%10 = OpTypeVector %8 3 +%9 = OpTypeMatrix %10 4 +%12 = OpTypeVector %8 2 %11 = OpTypeMatrix %12 2 %14 = OpConstant %3 2 %13 = OpTypeArray %11 %14 @@ -120,18 +120,18 @@ OpDecorate %272 Location 0 %17 = OpTypeVector %3 2 %18 = OpTypeArray %17 %14 %19 = OpTypeRuntimeArray %7 -%20 = OpTypeStruct %8 %13 %5 %15 %18 %19 +%20 = OpTypeStruct %9 %13 %5 %15 %18 %19 %21 = OpTypeMatrix %12 3 %22 = OpTypeStruct %21 %23 = OpTypeVector %5 2 %24 = OpTypeMatrix %12 4 %25 = OpTypeArray %24 %14 %26 = OpTypeStruct %25 -%27 = OpTypePointer Function %10 -%28 = OpTypeArray %10 %16 +%27 = OpTypePointer Function %8 +%28 = OpTypeArray %8 %16 %30 = OpConstant %3 5 %29 = OpTypeArray %28 %30 -%31 = OpTypeVector %10 4 +%31 = OpTypeVector %8 4 %32 = OpTypeArray %5 %30 %33 = OpTypePointer Function %3 %34 = OpTypeArray %31 %14 @@ -156,44 +156,44 @@ OpDecorate %272 Location 0 %55 = OpTypeFunction %2 %56 = OpTypePointer Uniform %22 %58 = OpConstant %5 1 -%59 = OpConstant %10 1.0 +%59 = OpConstant %8 1.0 %60 = OpConstantComposite %12 %59 %59 -%61 = OpConstant %10 2.0 +%61 = OpConstant %8 2.0 %62 = OpConstantComposite %12 %61 %61 -%63 = OpConstant %10 3.0 +%63 = OpConstant %8 3.0 %64 = OpConstantComposite %12 %63 %63 %65 = OpConstantComposite %21 %60 %62 %64 %66 = OpConstantComposite %22 %65 -%67 = OpConstant %10 6.0 +%67 = OpConstant %8 6.0 %68 = OpConstantComposite %12 %67 %67 -%69 = OpConstant %10 5.0 +%69 = OpConstant %8 5.0 %70 = OpConstantComposite %12 %69 %69 -%71 = OpConstant %10 4.0 +%71 = OpConstant %8 4.0 %72 = OpConstantComposite %12 %71 %71 %73 = OpConstantComposite %21 %68 %70 %72 -%74 = OpConstant %10 9.0 +%74 = OpConstant %8 9.0 %75 = OpConstantComposite %12 %74 %74 -%76 = OpConstant %10 90.0 +%76 = OpConstant %8 90.0 %77 = OpConstantComposite %12 %76 %76 -%78 = OpConstant %10 10.0 -%79 = OpConstant %10 20.0 -%80 = OpConstant %10 30.0 -%81 = OpConstant %10 40.0 +%78 = OpConstant %8 10.0 +%79 = OpConstant %8 20.0 +%80 = OpConstant %8 30.0 +%81 = OpConstant %8 40.0 %83 = OpTypePointer Function %5 %85 = OpTypePointer Function %22 %89 = OpTypePointer Uniform %21 %92 = OpTypePointer Uniform %12 -%98 = OpTypePointer Uniform %10 +%98 = OpTypePointer Uniform %8 %99 = OpConstant %3 1 %114 = OpTypePointer Function %21 %116 = OpTypePointer Function %12 -%120 = OpTypePointer Function %10 +%120 = OpTypePointer Function %8 %131 = OpTypePointer Uniform %26 %133 = OpConstantNull %25 %134 = OpConstantComposite %26 %133 -%135 = OpConstant %10 8.0 +%135 = OpConstant %8 8.0 %136 = OpConstantComposite %12 %135 %135 -%137 = OpConstant %10 7.0 +%137 = OpConstant %8 7.0 %138 = OpConstantComposite %12 %137 %137 %139 = OpConstantComposite %24 %136 %138 %68 %70 %142 = OpTypePointer Function %26 @@ -201,8 +201,8 @@ OpDecorate %272 Location 0 %149 = OpTypePointer Uniform %24 %171 = OpTypePointer Function %25 %173 = OpTypePointer Function %24 -%189 = OpTypeFunction %10 %27 -%195 = OpTypeFunction %10 %29 +%189 = OpTypeFunction %8 %27 +%195 = OpTypeFunction %8 %29 %202 = OpTypeFunction %2 %33 %203 = OpConstant %3 42 %208 = OpTypeFunction %2 %35 @@ -214,7 +214,7 @@ OpDecorate %272 Location 0 %218 = OpTypePointer Output %31 %217 = OpVariable %218 Output %221 = OpTypePointer StorageBuffer %23 -%224 = OpConstant %10 0.0 +%224 = OpConstant %8 0.0 %225 = OpConstant %3 3 %226 = OpConstant %5 3 %227 = OpConstant %5 4 @@ -223,21 +223,21 @@ OpDecorate %272 Location 0 %230 = OpConstantNull %29 %233 = OpTypePointer Function %32 %234 = OpConstantNull %32 -%239 = OpTypePointer StorageBuffer %8 +%239 = OpTypePointer StorageBuffer %9 %242 = OpTypePointer StorageBuffer %18 %243 = OpConstant %3 4 -%246 = OpTypePointer StorageBuffer %9 -%247 = OpTypePointer StorageBuffer %10 +%246 = OpTypePointer StorageBuffer %10 +%247 = OpTypePointer StorageBuffer %8 %250 = OpTypePointer StorageBuffer %19 %253 = OpTypePointer StorageBuffer %7 %254 = OpTypePointer StorageBuffer %5 %266 = OpTypeVector %5 4 %272 = OpVariable %218 Output -%275 = OpConstantComposite %9 %224 %224 %224 -%276 = OpConstantComposite %9 %59 %59 %59 -%277 = OpConstantComposite %9 %61 %61 %61 -%278 = OpConstantComposite %9 %63 %63 %63 -%279 = OpConstantComposite %8 %275 %276 %277 %278 +%275 = OpConstantComposite %10 %224 %224 %224 +%276 = OpConstantComposite %10 %59 %59 %59 +%277 = OpConstantComposite %10 %61 %61 %61 +%278 = OpConstantComposite %10 %63 %63 %63 +%279 = OpConstantComposite %9 %275 %276 %277 %278 %280 = OpConstantComposite %17 %36 %36 %281 = OpConstantComposite %17 %99 %99 %282 = OpConstantComposite %18 %280 %281 @@ -265,17 +265,17 @@ OpStore %82 %88 %96 = OpAccessChain %92 %57 %36 %95 %97 = OpLoad %12 %96 %100 = OpAccessChain %98 %57 %36 %36 %99 -%101 = OpLoad %10 %100 +%101 = OpLoad %8 %100 %102 = OpLoad %5 %82 %103 = OpAccessChain %98 %57 %36 %36 %102 -%104 = OpLoad %10 %103 +%104 = OpLoad %8 %103 %105 = OpLoad %5 %82 %106 = OpAccessChain %98 %57 %36 %105 %99 -%107 = OpLoad %10 %106 +%107 = OpLoad %8 %106 %108 = OpLoad %5 %82 %109 = OpLoad %5 %82 %110 = OpAccessChain %98 %57 %36 %108 %109 -%111 = OpLoad %10 %110 +%111 = OpLoad %8 %110 %112 = OpLoad %5 %82 %113 = OpIAdd %5 %112 %58 OpStore %82 %113 @@ -320,17 +320,17 @@ OpStore %140 %145 %155 = OpAccessChain %92 %132 %36 %36 %154 %156 = OpLoad %12 %155 %157 = OpAccessChain %98 %132 %36 %36 %36 %99 -%158 = OpLoad %10 %157 +%158 = OpLoad %8 %157 %159 = OpLoad %5 %140 %160 = OpAccessChain %98 %132 %36 %36 %36 %159 -%161 = OpLoad %10 %160 +%161 = OpLoad %8 %160 %162 = OpLoad %5 %140 %163 = OpAccessChain %98 %132 %36 %36 %162 %99 -%164 = OpLoad %10 %163 +%164 = OpLoad %8 %163 %165 = OpLoad %5 %140 %166 = OpLoad %5 %140 %167 = OpAccessChain %98 %132 %36 %36 %165 %166 -%168 = OpLoad %10 %167 +%168 = OpLoad %8 %167 %169 = OpLoad %5 %140 %170 = OpIAdd %5 %169 %58 OpStore %140 %170 @@ -357,21 +357,21 @@ OpStore %182 %80 OpStore %185 %81 OpReturn OpFunctionEnd -%188 = OpFunction %10 None %189 +%188 = OpFunction %8 None %189 %187 = OpFunctionParameter %27 %186 = OpLabel OpBranch %190 %190 = OpLabel -%191 = OpLoad %10 %187 +%191 = OpLoad %8 %187 OpReturnValue %191 OpFunctionEnd -%194 = OpFunction %10 None %195 +%194 = OpFunction %8 None %195 %193 = OpFunctionParameter %29 %192 = OpLabel OpBranch %196 %196 = OpLabel %197 = OpCompositeExtract %28 %193 4 -%198 = OpCompositeExtract %10 %197 9 +%198 = OpCompositeExtract %8 %197 9 OpReturnValue %198 OpFunctionEnd %201 = OpFunction %2 None %202 @@ -400,22 +400,22 @@ OpFunctionEnd %223 = OpAccessChain %131 %50 %36 OpBranch %235 %235 = OpLabel -%236 = OpLoad %10 %231 +%236 = OpLoad %8 %231 OpStore %231 %59 %237 = OpFunctionCall %2 %54 %238 = OpFunctionCall %2 %130 %240 = OpAccessChain %239 %42 %36 -%241 = OpLoad %8 %240 +%241 = OpLoad %9 %240 %244 = OpAccessChain %242 %42 %243 %245 = OpLoad %18 %244 %248 = OpAccessChain %247 %42 %36 %225 %36 -%249 = OpLoad %10 %248 +%249 = OpLoad %8 %248 %251 = OpArrayLength %3 %42 5 %252 = OpISub %3 %251 %14 %255 = OpAccessChain %254 %42 %30 %252 %36 %256 = OpLoad %5 %255 %257 = OpLoad %23 %222 -%258 = OpFunctionCall %10 %188 %231 +%258 = OpFunctionCall %8 %188 %231 %259 = OpConvertFToS %5 %249 %260 = OpCompositeConstruct %32 %256 %259 %226 %227 %228 OpStore %232 %260 @@ -424,10 +424,10 @@ OpStore %232 %260 OpStore %262 %229 %263 = OpAccessChain %83 %232 %216 %264 = OpLoad %5 %263 -%265 = OpFunctionCall %10 %194 %230 +%265 = OpFunctionCall %8 %194 %230 %267 = OpCompositeConstruct %266 %264 %264 %264 %264 %268 = OpConvertSToF %31 %267 -%269 = OpMatrixTimesVector %9 %241 %268 +%269 = OpMatrixTimesVector %10 %241 %268 %270 = OpCompositeConstruct %31 %269 %61 OpStore %217 %270 OpReturn diff --git a/naga/tests/out/spv/boids.spvasm b/naga/tests/out/spv/boids.spvasm index 0e48e0f559..4fc1cbf49f 100644 --- a/naga/tests/out/spv/boids.spvasm +++ b/naga/tests/out/spv/boids.spvasm @@ -61,10 +61,10 @@ OpDecorate %18 Binding 2 OpDecorate %20 BuiltIn GlobalInvocationId %2 = OpTypeVoid %3 = OpTypeInt 32 0 -%5 = OpTypeFloat 32 -%4 = OpTypeVector %5 2 -%6 = OpTypeStruct %4 %4 -%7 = OpTypeStruct %5 %5 %5 %5 %5 %5 %5 +%4 = OpTypeFloat 32 +%5 = OpTypeVector %4 2 +%6 = OpTypeStruct %5 %5 +%7 = OpTypeStruct %4 %4 %4 %4 %4 %4 %4 %8 = OpTypeRuntimeArray %6 %9 = OpTypeStruct %8 %10 = OpTypeVector %3 3 @@ -81,32 +81,32 @@ OpDecorate %20 BuiltIn GlobalInvocationId %24 = OpTypeFunction %2 %25 = OpTypePointer Uniform %7 %26 = OpConstant %3 0 -%28 = OpConstant %5 0.0 -%29 = OpConstantComposite %4 %28 %28 +%28 = OpConstant %4 0.0 +%29 = OpConstantComposite %5 %28 %28 %30 = OpConstant %11 0 %31 = OpConstant %11 1 %32 = OpConstant %3 1 -%33 = OpConstant %5 0.1 -%34 = OpConstant %5 -1.0 -%35 = OpConstant %5 1.0 -%37 = OpTypePointer Function %4 -%38 = OpConstantNull %4 -%40 = OpConstantNull %4 +%33 = OpConstant %4 0.1 +%34 = OpConstant %4 -1.0 +%35 = OpConstant %4 1.0 +%37 = OpTypePointer Function %5 +%38 = OpConstantNull %5 +%40 = OpConstantNull %5 %45 = OpTypePointer Function %11 -%48 = OpConstantNull %4 -%50 = OpConstantNull %4 +%48 = OpConstantNull %5 +%50 = OpConstantNull %5 %52 = OpTypePointer Function %3 %55 = OpTypeBool %59 = OpTypePointer StorageBuffer %8 %60 = OpTypePointer StorageBuffer %6 -%61 = OpTypePointer StorageBuffer %4 -%87 = OpTypePointer Uniform %5 +%61 = OpTypePointer StorageBuffer %5 +%87 = OpTypePointer Uniform %4 %101 = OpConstant %3 2 %115 = OpConstant %3 3 %150 = OpConstant %3 4 %156 = OpConstant %3 5 %162 = OpConstant %3 6 -%179 = OpTypePointer Function %5 +%179 = OpTypePointer Function %4 %23 = OpFunction %2 None %24 %19 = OpLabel %51 = OpVariable %52 Function %26 @@ -131,10 +131,10 @@ OpBranchConditional %56 %58 %57 OpReturn %57 = OpLabel %62 = OpAccessChain %61 %16 %26 %54 %26 -%63 = OpLoad %4 %62 +%63 = OpLoad %5 %62 OpStore %36 %63 %64 = OpAccessChain %61 %16 %26 %54 %32 -%65 = OpLoad %4 %64 +%65 = OpLoad %5 %64 OpStore %39 %65 OpBranch %66 %66 = OpLabel @@ -157,59 +157,59 @@ OpBranch %69 %76 = OpLabel %78 = OpLoad %3 %51 %79 = OpAccessChain %61 %16 %26 %78 %26 -%80 = OpLoad %4 %79 +%80 = OpLoad %5 %79 OpStore %47 %80 %81 = OpLoad %3 %51 %82 = OpAccessChain %61 %16 %26 %81 %32 -%83 = OpLoad %4 %82 +%83 = OpLoad %5 %82 OpStore %49 %83 -%84 = OpLoad %4 %47 -%85 = OpLoad %4 %36 -%86 = OpExtInst %5 %1 Distance %84 %85 +%84 = OpLoad %5 %47 +%85 = OpLoad %5 %36 +%86 = OpExtInst %4 %1 Distance %84 %85 %88 = OpAccessChain %87 %27 %32 -%89 = OpLoad %5 %88 +%89 = OpLoad %4 %88 %90 = OpFOrdLessThan %55 %86 %89 OpSelectionMerge %91 None OpBranchConditional %90 %92 %91 %92 = OpLabel -%93 = OpLoad %4 %41 -%94 = OpLoad %4 %47 -%95 = OpFAdd %4 %93 %94 +%93 = OpLoad %5 %41 +%94 = OpLoad %5 %47 +%95 = OpFAdd %5 %93 %94 OpStore %41 %95 %96 = OpLoad %11 %44 %97 = OpIAdd %11 %96 %31 OpStore %44 %97 OpBranch %91 %91 = OpLabel -%98 = OpLoad %4 %47 -%99 = OpLoad %4 %36 -%100 = OpExtInst %5 %1 Distance %98 %99 +%98 = OpLoad %5 %47 +%99 = OpLoad %5 %36 +%100 = OpExtInst %4 %1 Distance %98 %99 %102 = OpAccessChain %87 %27 %101 -%103 = OpLoad %5 %102 +%103 = OpLoad %4 %102 %104 = OpFOrdLessThan %55 %100 %103 OpSelectionMerge %105 None OpBranchConditional %104 %106 %105 %106 = OpLabel -%107 = OpLoad %4 %43 -%108 = OpLoad %4 %47 -%109 = OpLoad %4 %36 -%110 = OpFSub %4 %108 %109 -%111 = OpFSub %4 %107 %110 +%107 = OpLoad %5 %43 +%108 = OpLoad %5 %47 +%109 = OpLoad %5 %36 +%110 = OpFSub %5 %108 %109 +%111 = OpFSub %5 %107 %110 OpStore %43 %111 OpBranch %105 %105 = OpLabel -%112 = OpLoad %4 %47 -%113 = OpLoad %4 %36 -%114 = OpExtInst %5 %1 Distance %112 %113 +%112 = OpLoad %5 %47 +%113 = OpLoad %5 %36 +%114 = OpExtInst %4 %1 Distance %112 %113 %116 = OpAccessChain %87 %27 %115 -%117 = OpLoad %5 %116 +%117 = OpLoad %4 %116 %118 = OpFOrdLessThan %55 %114 %117 OpSelectionMerge %119 None OpBranchConditional %118 %120 %119 %120 = OpLabel -%121 = OpLoad %4 %42 -%122 = OpLoad %4 %49 -%123 = OpFAdd %4 %121 %122 +%121 = OpLoad %5 %42 +%122 = OpLoad %5 %49 +%123 = OpFAdd %5 %121 %122 OpStore %42 %123 %124 = OpLoad %11 %46 %125 = OpIAdd %11 %124 %31 @@ -228,13 +228,13 @@ OpBranch %66 OpSelectionMerge %130 None OpBranchConditional %129 %131 %130 %131 = OpLabel -%132 = OpLoad %4 %41 +%132 = OpLoad %5 %41 %133 = OpLoad %11 %44 -%134 = OpConvertSToF %5 %133 -%135 = OpCompositeConstruct %4 %134 %134 -%136 = OpFDiv %4 %132 %135 -%137 = OpLoad %4 %36 -%138 = OpFSub %4 %136 %137 +%134 = OpConvertSToF %4 %133 +%135 = OpCompositeConstruct %5 %134 %134 +%136 = OpFDiv %5 %132 %135 +%137 = OpLoad %5 %36 +%138 = OpFSub %5 %136 %137 OpStore %41 %138 OpBranch %130 %130 = OpLabel @@ -243,47 +243,47 @@ OpBranch %130 OpSelectionMerge %141 None OpBranchConditional %140 %142 %141 %142 = OpLabel -%143 = OpLoad %4 %42 +%143 = OpLoad %5 %42 %144 = OpLoad %11 %46 -%145 = OpConvertSToF %5 %144 -%146 = OpCompositeConstruct %4 %145 %145 -%147 = OpFDiv %4 %143 %146 +%145 = OpConvertSToF %4 %144 +%146 = OpCompositeConstruct %5 %145 %145 +%147 = OpFDiv %5 %143 %146 OpStore %42 %147 OpBranch %141 %141 = OpLabel -%148 = OpLoad %4 %39 -%149 = OpLoad %4 %41 +%148 = OpLoad %5 %39 +%149 = OpLoad %5 %41 %151 = OpAccessChain %87 %27 %150 -%152 = OpLoad %5 %151 -%153 = OpVectorTimesScalar %4 %149 %152 -%154 = OpFAdd %4 %148 %153 -%155 = OpLoad %4 %43 +%152 = OpLoad %4 %151 +%153 = OpVectorTimesScalar %5 %149 %152 +%154 = OpFAdd %5 %148 %153 +%155 = OpLoad %5 %43 %157 = OpAccessChain %87 %27 %156 -%158 = OpLoad %5 %157 -%159 = OpVectorTimesScalar %4 %155 %158 -%160 = OpFAdd %4 %154 %159 -%161 = OpLoad %4 %42 +%158 = OpLoad %4 %157 +%159 = OpVectorTimesScalar %5 %155 %158 +%160 = OpFAdd %5 %154 %159 +%161 = OpLoad %5 %42 %163 = OpAccessChain %87 %27 %162 -%164 = OpLoad %5 %163 -%165 = OpVectorTimesScalar %4 %161 %164 -%166 = OpFAdd %4 %160 %165 +%164 = OpLoad %4 %163 +%165 = OpVectorTimesScalar %5 %161 %164 +%166 = OpFAdd %5 %160 %165 OpStore %39 %166 -%167 = OpLoad %4 %39 -%168 = OpExtInst %4 %1 Normalize %167 -%169 = OpLoad %4 %39 -%170 = OpExtInst %5 %1 Length %169 -%171 = OpExtInst %5 %1 FClamp %170 %28 %33 -%172 = OpVectorTimesScalar %4 %168 %171 +%167 = OpLoad %5 %39 +%168 = OpExtInst %5 %1 Normalize %167 +%169 = OpLoad %5 %39 +%170 = OpExtInst %4 %1 Length %169 +%171 = OpExtInst %4 %1 FClamp %170 %28 %33 +%172 = OpVectorTimesScalar %5 %168 %171 OpStore %39 %172 -%173 = OpLoad %4 %36 -%174 = OpLoad %4 %39 +%173 = OpLoad %5 %36 +%174 = OpLoad %5 %39 %175 = OpAccessChain %87 %27 %26 -%176 = OpLoad %5 %175 -%177 = OpVectorTimesScalar %4 %174 %176 -%178 = OpFAdd %4 %173 %177 +%176 = OpLoad %4 %175 +%177 = OpVectorTimesScalar %5 %174 %176 +%178 = OpFAdd %5 %173 %177 OpStore %36 %178 %180 = OpAccessChain %179 %36 %26 -%181 = OpLoad %5 %180 +%181 = OpLoad %4 %180 %182 = OpFOrdLessThan %55 %181 %34 OpSelectionMerge %183 None OpBranchConditional %182 %184 %183 @@ -293,7 +293,7 @@ OpStore %185 %35 OpBranch %183 %183 = OpLabel %186 = OpAccessChain %179 %36 %26 -%187 = OpLoad %5 %186 +%187 = OpLoad %4 %186 %188 = OpFOrdGreaterThan %55 %187 %35 OpSelectionMerge %189 None OpBranchConditional %188 %190 %189 @@ -303,7 +303,7 @@ OpStore %191 %34 OpBranch %189 %189 = OpLabel %192 = OpAccessChain %179 %36 %32 -%193 = OpLoad %5 %192 +%193 = OpLoad %4 %192 %194 = OpFOrdLessThan %55 %193 %34 OpSelectionMerge %195 None OpBranchConditional %194 %196 %195 @@ -313,7 +313,7 @@ OpStore %197 %35 OpBranch %195 %195 = OpLabel %198 = OpAccessChain %179 %36 %32 -%199 = OpLoad %5 %198 +%199 = OpLoad %4 %198 %200 = OpFOrdGreaterThan %55 %199 %35 OpSelectionMerge %201 None OpBranchConditional %200 %202 %201 @@ -322,10 +322,10 @@ OpBranchConditional %200 %202 %201 OpStore %203 %34 OpBranch %201 %201 = OpLabel -%204 = OpLoad %4 %36 +%204 = OpLoad %5 %36 %205 = OpAccessChain %61 %18 %26 %54 %26 OpStore %205 %204 -%206 = OpLoad %4 %39 +%206 = OpLoad %5 %39 %207 = OpAccessChain %61 %18 %26 %54 %32 OpStore %207 %206 OpReturn diff --git a/naga/tests/out/spv/const-exprs.spvasm b/naga/tests/out/spv/const-exprs.spvasm index 22fef53749..afd9fe8499 100644 --- a/naga/tests/out/spv/const-exprs.spvasm +++ b/naga/tests/out/spv/const-exprs.spvasm @@ -11,25 +11,25 @@ OpExecutionMode %100 LocalSize 2 3 1 %3 = OpTypeInt 32 0 %4 = OpTypeInt 32 1 %5 = OpTypeVector %4 4 -%7 = OpTypeFloat 32 -%6 = OpTypeVector %7 4 -%8 = OpTypeVector %7 2 +%6 = OpTypeFloat 32 +%7 = OpTypeVector %6 4 +%8 = OpTypeVector %6 2 %10 = OpTypeBool %9 = OpTypeVector %10 2 %11 = OpConstant %3 2 %12 = OpConstant %4 3 %13 = OpConstant %4 4 %14 = OpConstant %4 8 -%15 = OpConstant %7 3.141 -%16 = OpConstant %7 6.282 -%17 = OpConstant %7 0.44444445 -%18 = OpConstant %7 0.0 -%19 = OpConstantComposite %6 %17 %18 %18 %18 +%15 = OpConstant %6 3.141 +%16 = OpConstant %6 6.282 +%17 = OpConstant %6 0.44444445 +%18 = OpConstant %6 0.0 +%19 = OpConstantComposite %7 %17 %18 %18 %18 %20 = OpConstant %4 0 %21 = OpConstant %4 1 %22 = OpConstant %4 2 -%23 = OpConstant %7 4.0 -%24 = OpConstant %7 5.0 +%23 = OpConstant %6 4.0 +%24 = OpConstant %6 5.0 %25 = OpConstantComposite %8 %23 %24 %26 = OpConstantTrue %10 %27 = OpConstantFalse %10 @@ -46,10 +46,10 @@ OpExecutionMode %100 LocalSize 2 3 1 %57 = OpConstantNull %5 %68 = OpConstant %4 -4 %69 = OpConstantComposite %5 %68 %68 %68 %68 -%78 = OpConstant %7 1.0 -%79 = OpConstant %7 2.0 -%80 = OpConstantComposite %6 %79 %78 %78 %78 -%82 = OpTypePointer Function %6 +%78 = OpConstant %6 1.0 +%79 = OpConstant %6 2.0 +%80 = OpConstantComposite %7 %79 %78 %78 %78 +%82 = OpTypePointer Function %7 %87 = OpTypeFunction %3 %4 %88 = OpConstant %3 10 %89 = OpConstant %3 20 diff --git a/naga/tests/out/spv/constructors.spvasm b/naga/tests/out/spv/constructors.spvasm index 615a31dc1b..ec83d04822 100644 --- a/naga/tests/out/spv/constructors.spvasm +++ b/naga/tests/out/spv/constructors.spvasm @@ -13,12 +13,12 @@ OpDecorate %10 ArrayStride 16 OpDecorate %15 ArrayStride 32 OpDecorate %17 ArrayStride 4 %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 %5 = OpTypeInt 32 1 -%6 = OpTypeStruct %3 %5 -%7 = OpTypeVector %4 3 -%9 = OpTypeVector %4 2 +%6 = OpTypeStruct %4 %5 +%7 = OpTypeVector %3 3 +%9 = OpTypeVector %3 2 %8 = OpTypeMatrix %9 2 %12 = OpTypeInt 32 0 %11 = OpConstant %12 1 @@ -29,13 +29,13 @@ OpDecorate %17 ArrayStride 4 %15 = OpTypeArray %6 %16 %18 = OpConstant %12 4 %17 = OpTypeArray %5 %18 -%19 = OpTypeMatrix %3 4 +%19 = OpTypeMatrix %4 4 %20 = OpTypeMatrix %7 2 -%21 = OpConstant %4 0.0 -%22 = OpConstant %4 1.0 -%23 = OpConstant %4 2.0 +%21 = OpConstant %3 0.0 +%22 = OpConstant %3 1.0 +%23 = OpConstant %3 2.0 %24 = OpConstantComposite %7 %21 %22 %23 -%25 = OpConstant %4 3.0 +%25 = OpConstant %3 3.0 %26 = OpConstantComposite %9 %21 %22 %27 = OpConstantComposite %9 %23 %25 %28 = OpConstantComposite %8 %26 %27 @@ -43,7 +43,7 @@ OpDecorate %17 ArrayStride 4 %30 = OpConstantNull %13 %31 = OpConstantNull %5 %32 = OpConstantNull %12 -%33 = OpConstantNull %4 +%33 = OpConstantNull %3 %34 = OpConstantNull %14 %35 = OpConstantNull %8 %36 = OpConstantNull %15 @@ -54,14 +54,14 @@ OpDecorate %17 ArrayStride 4 %41 = OpConstant %5 3 %42 = OpConstantComposite %17 %38 %39 %40 %41 %45 = OpTypeFunction %2 -%46 = OpConstantComposite %3 %22 %22 %22 %22 +%46 = OpConstantComposite %4 %22 %22 %22 %22 %47 = OpConstantComposite %6 %46 %39 %48 = OpConstantComposite %9 %22 %21 %49 = OpConstantComposite %8 %48 %26 -%50 = OpConstantComposite %3 %22 %21 %21 %21 -%51 = OpConstantComposite %3 %21 %22 %21 %21 -%52 = OpConstantComposite %3 %21 %21 %22 %21 -%53 = OpConstantComposite %3 %21 %21 %21 %22 +%50 = OpConstantComposite %4 %22 %21 %21 %21 +%51 = OpConstantComposite %4 %21 %22 %21 %21 +%52 = OpConstantComposite %4 %21 %21 %22 %21 +%53 = OpConstantComposite %4 %21 %21 %21 %22 %54 = OpConstantComposite %19 %50 %51 %52 %53 %55 = OpConstant %12 0 %56 = OpConstantComposite %14 %55 %55 diff --git a/naga/tests/out/spv/cross.spvasm b/naga/tests/out/spv/cross.spvasm new file mode 100644 index 0000000000..b41479900c --- /dev/null +++ b/naga/tests/out/spv/cross.spvasm @@ -0,0 +1,24 @@ +; SPIR-V +; Version: 1.1 +; Generator: rspirv +; Bound: 14 +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %6 "main" +OpExecutionMode %6 LocalSize 1 1 1 +%2 = OpTypeVoid +%4 = OpTypeFloat 32 +%3 = OpTypeVector %4 3 +%7 = OpTypeFunction %2 +%8 = OpConstant %4 0.0 +%9 = OpConstant %4 1.0 +%10 = OpConstant %4 2.0 +%11 = OpConstantComposite %3 %8 %9 %10 +%6 = OpFunction %2 None %7 +%5 = OpLabel +OpBranch %12 +%12 = OpLabel +%13 = OpExtInst %3 %1 Cross %11 %11 +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/debug-symbol-large-source.spvasm b/naga/tests/out/spv/debug-symbol-large-source.spvasm index 47a6fb77aa..15e95cf2a5 100644 --- a/naga/tests/out/spv/debug-symbol-large-source.spvasm +++ b/naga/tests/out/spv/debug-symbol-large-source.spvasm @@ -7653,17 +7653,17 @@ OpDecorate %578 Location 0 OpDecorate %580 Location 1 OpDecorate %582 Location 0 %2 = OpTypeVoid -%5 = OpTypeFloat 32 -%4 = OpTypeVector %5 3 -%6 = OpTypeVector %5 2 -%7 = OpTypeVector %5 4 +%4 = OpTypeFloat 32 +%5 = OpTypeVector %4 3 +%6 = OpTypeVector %4 2 +%7 = OpTypeVector %4 4 %8 = OpTypeInt 32 0 %9 = OpTypeMatrix %6 2 %10 = OpTypeVector %8 2 %12 = OpTypeInt 32 1 %11 = OpTypeVector %12 2 %13 = OpTypeStruct %10 %11 %6 -%14 = OpTypeStruct %4 %4 +%14 = OpTypeStruct %5 %5 %15 = OpTypeRuntimeArray %14 %16 = OpTypeStruct %15 %17 = OpTypeRuntimeArray %8 @@ -7674,9 +7674,9 @@ OpDecorate %582 Location 0 %22 = OpTypeStruct %8 %8 %23 = OpTypeMatrix %7 4 %24 = OpTypeStruct %7 %23 -%25 = OpTypeStruct %4 %4 -%26 = OpTypeStruct %7 %4 %4 -%27 = OpTypeImage %5 2D 0 0 0 1 Unknown +%25 = OpTypeStruct %5 %5 +%26 = OpTypeStruct %7 %5 %5 +%27 = OpTypeImage %4 2D 0 0 0 1 Unknown %28 = OpTypeSampler %30 = OpTypeStruct %13 %31 = OpTypePointer Uniform %30 @@ -7700,67 +7700,67 @@ OpDecorate %582 Location 0 %47 = OpVariable %48 UniformConstant %49 = OpVariable %46 UniformConstant %50 = OpVariable %48 UniformConstant -%54 = OpTypeFunction %4 %4 -%55 = OpConstant %5 34.0 -%56 = OpConstant %5 1.0 -%57 = OpConstantComposite %4 %56 %56 %56 -%58 = OpConstant %5 289.0 -%59 = OpConstantComposite %4 %58 %58 %58 -%68 = OpTypeFunction %5 %6 -%69 = OpConstant %5 0.21132487 -%70 = OpConstant %5 0.36602542 -%71 = OpConstant %5 -0.57735026 -%72 = OpConstant %5 0.024390243 +%54 = OpTypeFunction %5 %5 +%55 = OpConstant %4 34.0 +%56 = OpConstant %4 1.0 +%57 = OpConstantComposite %5 %56 %56 %56 +%58 = OpConstant %4 289.0 +%59 = OpConstantComposite %5 %58 %58 %58 +%68 = OpTypeFunction %4 %6 +%69 = OpConstant %4 0.21132487 +%70 = OpConstant %4 0.36602542 +%71 = OpConstant %4 -0.57735026 +%72 = OpConstant %4 0.024390243 %73 = OpConstantComposite %7 %69 %70 %71 %72 -%74 = OpConstant %5 0.0 +%74 = OpConstant %4 0.0 %75 = OpConstantComposite %6 %56 %74 %76 = OpConstantComposite %6 %74 %56 %77 = OpConstantComposite %6 %58 %58 -%78 = OpConstant %5 0.5 -%79 = OpConstantComposite %4 %78 %78 %78 -%80 = OpConstantComposite %4 %74 %74 %74 -%81 = OpConstant %5 2.0 -%82 = OpConstant %5 0.85373473 -%83 = OpConstant %5 1.7928429 -%84 = OpConstantComposite %4 %83 %83 %83 -%85 = OpConstant %5 130.0 +%78 = OpConstant %4 0.5 +%79 = OpConstantComposite %5 %78 %78 %78 +%80 = OpConstantComposite %5 %74 %74 %74 +%81 = OpConstant %4 2.0 +%82 = OpConstant %4 0.85373473 +%83 = OpConstant %4 1.7928429 +%84 = OpConstantComposite %5 %83 %83 %83 +%85 = OpConstant %4 130.0 %87 = OpTypePointer Function %6 %88 = OpConstantNull %6 %90 = OpConstantNull %6 %92 = OpTypePointer Function %7 %93 = OpConstantNull %7 -%95 = OpTypePointer Function %4 -%96 = OpConstantNull %4 +%95 = OpTypePointer Function %5 +%96 = OpConstantNull %5 %112 = OpTypeBool %115 = OpTypeVector %112 2 -%125 = OpTypePointer Function %5 +%125 = OpTypePointer Function %4 %126 = OpConstant %8 1 %135 = OpConstant %8 0 %205 = OpConstant %8 5 -%206 = OpConstant %5 0.01 -%207 = OpConstant %5 100.0 +%206 = OpConstant %4 0.01 +%207 = OpConstant %4 100.0 %208 = OpConstantComposite %6 %207 %207 -%209 = OpConstant %5 0.87758255 -%210 = OpConstant %5 0.47942555 +%209 = OpConstant %4 0.87758255 +%210 = OpConstant %4 0.47942555 %211 = OpConstantComposite %6 %209 %210 %213 = OpConstantNull %6 -%215 = OpTypePointer Function %5 +%215 = OpTypePointer Function %4 %218 = OpTypePointer Function %8 -%258 = OpTypeFunction %4 %6 %6 +%258 = OpTypeFunction %5 %6 %6 %271 = OpTypeFunction %14 %6 %6 -%272 = OpConstant %5 0.1 +%272 = OpConstant %4 0.1 %273 = OpConstantComposite %6 %272 %74 %274 = OpConstantComposite %6 %74 %272 -%275 = OpConstant %5 -0.1 +%275 = OpConstant %4 -0.1 %276 = OpConstantComposite %6 %275 %74 %277 = OpConstantComposite %6 %74 %275 %304 = OpTypeFunction %6 %8 %10 %11 -%321 = OpTypeFunction %4 %6 -%322 = OpConstant %5 23.0 -%323 = OpConstant %5 32.0 +%321 = OpTypeFunction %5 %6 +%322 = OpConstant %4 23.0 +%323 = OpConstant %4 32.0 %324 = OpConstantComposite %6 %322 %323 -%325 = OpConstant %5 -43.0 -%326 = OpConstant %5 3.0 +%325 = OpConstant %4 -43.0 +%326 = OpConstant %4 3.0 %327 = OpConstantComposite %6 %325 %326 %343 = OpTypePointer Input %19 %342 = OpVariable %343 Input @@ -7787,7 +7787,7 @@ OpDecorate %582 Location 0 %414 = OpTypePointer Output %6 %413 = OpVariable %414 Output %416 = OpTypePointer Uniform %20 -%418 = OpConstant %5 -1.0 +%418 = OpConstant %4 -1.0 %419 = OpConstantComposite %6 %418 %418 %434 = OpTypePointer Uniform %8 %455 = OpVariable %407 Input @@ -7797,12 +7797,12 @@ OpDecorate %582 Location 0 %460 = OpVariable %461 Input %463 = OpVariable %410 Output %464 = OpVariable %410 Output -%467 = OpConstant %5 6.0 -%550 = OpTypePointer Input %4 +%467 = OpConstant %4 6.0 +%550 = OpTypePointer Input %5 %549 = OpVariable %550 Input %552 = OpVariable %550 Input %554 = OpVariable %412 Output -%556 = OpTypePointer Output %4 +%556 = OpTypePointer Output %5 %555 = OpVariable %556 Output %557 = OpVariable %556 Output %559 = OpTypePointer Uniform %24 @@ -7812,30 +7812,30 @@ OpDecorate %582 Location 0 %580 = OpVariable %550 Input %582 = OpVariable %412 Output %585 = OpTypePointer Uniform %25 -%587 = OpConstantComposite %4 %272 %272 %272 -%588 = OpConstant %5 0.7 -%589 = OpConstantComposite %4 %78 %272 %588 -%590 = OpConstant %5 0.2 -%591 = OpConstantComposite %4 %590 %590 %590 -%593 = OpConstantNull %4 -%608 = OpTypePointer Uniform %4 +%587 = OpConstantComposite %5 %272 %272 %272 +%588 = OpConstant %4 0.7 +%589 = OpConstantComposite %5 %78 %272 %588 +%590 = OpConstant %4 0.2 +%591 = OpConstantComposite %5 %590 %590 %590 +%593 = OpConstantNull %5 +%608 = OpTypePointer Uniform %5 %617 = OpTypePointer Uniform %7 -%53 = OpFunction %4 None %54 -%52 = OpFunctionParameter %4 +%53 = OpFunction %5 None %54 +%52 = OpFunctionParameter %5 %51 = OpLabel OpBranch %60 %60 = OpLabel OpLine %3 5734 52 -%61 = OpVectorTimesScalar %4 %52 %55 +%61 = OpVectorTimesScalar %5 %52 %55 OpLine %3 5734 63 OpLine %3 5734 50 -%62 = OpFAdd %4 %61 %57 -%63 = OpFMul %4 %62 %52 +%62 = OpFAdd %5 %61 %57 +%63 = OpFMul %5 %62 %52 OpLine %3 5734 49 -%64 = OpFRem %4 %63 %59 +%64 = OpFRem %5 %63 %59 OpReturnValue %64 OpFunctionEnd -%67 = OpFunction %5 None %68 +%67 = OpFunction %4 None %68 %66 = OpFunctionParameter %6 %65 = OpLabel %89 = OpVariable %87 Function %90 @@ -7847,7 +7847,7 @@ OpBranch %97 OpLine %3 5737 13 OpLine %3 5738 24 %98 = OpVectorShuffle %6 %73 %73 1 1 -%99 = OpDot %5 %66 %98 +%99 = OpDot %4 %66 %98 %100 = OpCompositeConstruct %6 %99 %99 %101 = OpFAdd %6 %66 %100 %102 = OpExtInst %6 %1 Floor %101 @@ -7858,13 +7858,13 @@ OpLine %3 5739 14 %104 = OpFSub %6 %66 %103 %105 = OpLoad %6 %86 %106 = OpVectorShuffle %6 %73 %73 0 0 -%107 = OpDot %5 %105 %106 +%107 = OpDot %4 %105 %106 %108 = OpCompositeConstruct %6 %107 %107 %109 = OpFAdd %6 %104 %108 OpLine %3 5741 32 OpLine %3 5741 25 -%110 = OpCompositeExtract %5 %109 0 -%111 = OpCompositeExtract %5 %109 1 +%110 = OpCompositeExtract %4 %109 0 +%111 = OpCompositeExtract %4 %109 1 %113 = OpFOrdLessThan %112 %110 %111 %116 = OpCompositeConstruct %115 %113 %113 %114 = OpSelect %6 %116 %76 %75 @@ -7888,101 +7888,101 @@ OpLine %3 5743 5 OpStore %86 %124 OpLine %3 5744 31 %127 = OpAccessChain %125 %86 %126 -%128 = OpLoad %5 %127 +%128 = OpLoad %4 %127 OpLine %3 5744 51 %129 = OpAccessChain %125 %89 %126 -%130 = OpLoad %5 %129 +%130 = OpLoad %4 %129 OpLine %3 5744 31 -%131 = OpCompositeConstruct %4 %74 %130 %56 -%132 = OpCompositeConstruct %4 %128 %128 %128 -%133 = OpFAdd %4 %132 %131 +%131 = OpCompositeConstruct %5 %74 %130 %56 +%132 = OpCompositeConstruct %5 %128 %128 %128 +%133 = OpFAdd %5 %132 %131 OpLine %3 5744 22 -%134 = OpFunctionCall %4 %53 %133 +%134 = OpFunctionCall %5 %53 %133 OpLine %3 5744 22 %136 = OpAccessChain %125 %86 %135 -%137 = OpLoad %5 %136 -%138 = OpCompositeConstruct %4 %137 %137 %137 -%139 = OpFAdd %4 %134 %138 +%137 = OpLoad %4 %136 +%138 = OpCompositeConstruct %5 %137 %137 %137 +%139 = OpFAdd %5 %134 %138 OpLine %3 5744 84 %140 = OpAccessChain %125 %89 %135 -%141 = OpLoad %5 %140 +%141 = OpLoad %4 %140 OpLine %3 5744 22 -%142 = OpCompositeConstruct %4 %74 %141 %56 -%143 = OpFAdd %4 %139 %142 +%142 = OpCompositeConstruct %5 %74 %141 %56 +%143 = OpFAdd %5 %139 %142 OpLine %3 5744 13 -%144 = OpFunctionCall %4 %53 %143 +%144 = OpFunctionCall %5 %53 %143 OpLine %3 5745 28 -%145 = OpDot %5 %109 %109 +%145 = OpDot %4 %109 %109 %146 = OpLoad %7 %91 %147 = OpVectorShuffle %6 %146 %146 0 1 %148 = OpLoad %7 %91 %149 = OpVectorShuffle %6 %148 %148 0 1 -%150 = OpDot %5 %147 %149 +%150 = OpDot %4 %147 %149 %151 = OpLoad %7 %91 %152 = OpVectorShuffle %6 %151 %151 2 3 %153 = OpLoad %7 %91 %154 = OpVectorShuffle %6 %153 %153 2 3 -%155 = OpDot %5 %152 %154 -%156 = OpCompositeConstruct %4 %145 %150 %155 +%155 = OpDot %4 %152 %154 +%156 = OpCompositeConstruct %5 %145 %150 %155 OpLine %3 5745 28 -%157 = OpFSub %4 %79 %156 +%157 = OpFSub %5 %79 %156 OpLine %3 5745 24 -%158 = OpExtInst %4 %1 FMax %157 %80 +%158 = OpExtInst %5 %1 FMax %157 %80 OpLine %3 5745 5 OpStore %94 %158 OpLine %3 5746 9 -%159 = OpLoad %4 %94 -%160 = OpLoad %4 %94 -%161 = OpFMul %4 %159 %160 +%159 = OpLoad %5 %94 +%160 = OpLoad %5 %94 +%161 = OpFMul %5 %159 %160 OpLine %3 5746 5 OpStore %94 %161 OpLine %3 5747 9 -%162 = OpLoad %4 %94 -%163 = OpLoad %4 %94 -%164 = OpFMul %4 %162 %163 +%162 = OpLoad %5 %94 +%163 = OpLoad %5 %94 +%164 = OpFMul %5 %162 %163 OpLine %3 5747 5 OpStore %94 %164 OpLine %3 5748 18 -%165 = OpVectorShuffle %4 %73 %73 3 3 3 -%166 = OpFMul %4 %144 %165 -%167 = OpExtInst %4 %1 Fract %166 +%165 = OpVectorShuffle %5 %73 %73 3 3 3 +%166 = OpFMul %5 %144 %165 +%167 = OpExtInst %5 %1 Fract %166 OpLine %3 5748 13 -%168 = OpVectorTimesScalar %4 %167 %81 +%168 = OpVectorTimesScalar %5 %167 %81 OpLine %3 5748 37 OpLine %3 5748 13 -%169 = OpFSub %4 %168 %57 +%169 = OpFSub %5 %168 %57 OpLine %3 5749 13 -%170 = OpExtInst %4 %1 FAbs %169 +%170 = OpExtInst %5 %1 FAbs %169 OpLine %3 5749 22 OpLine %3 5749 13 -%171 = OpFSub %4 %170 %79 +%171 = OpFSub %5 %170 %79 OpLine %3 7169 24 OpLine %3 7169 14 -%172 = OpFAdd %4 %169 %79 -%173 = OpExtInst %4 %1 Floor %172 +%172 = OpFAdd %5 %169 %79 +%173 = OpExtInst %5 %1 Floor %172 OpLine %3 7170 14 -%174 = OpFSub %4 %169 %173 +%174 = OpFSub %5 %169 %173 OpLine %3 1 1 -%175 = OpLoad %4 %94 +%175 = OpLoad %5 %94 OpLine %3 7171 53 -%176 = OpFMul %4 %174 %174 -%177 = OpFMul %4 %171 %171 -%178 = OpFAdd %4 %176 %177 +%176 = OpFMul %5 %174 %174 +%177 = OpFMul %5 %171 %171 +%178 = OpFAdd %5 %176 %177 OpLine %3 7171 14 -%179 = OpVectorTimesScalar %4 %178 %82 +%179 = OpVectorTimesScalar %5 %178 %82 OpLine %3 7171 9 -%180 = OpFSub %4 %84 %179 -%181 = OpFMul %4 %175 %180 +%180 = OpFSub %5 %84 %179 +%181 = OpFMul %5 %175 %180 OpLine %3 7171 5 OpStore %94 %181 OpLine %3 7172 13 -%182 = OpCompositeExtract %5 %174 0 -%183 = OpCompositeExtract %5 %109 0 -%184 = OpFMul %5 %182 %183 -%185 = OpCompositeExtract %5 %171 0 -%186 = OpCompositeExtract %5 %109 1 -%187 = OpFMul %5 %185 %186 -%188 = OpFAdd %5 %184 %187 +%182 = OpCompositeExtract %4 %174 0 +%183 = OpCompositeExtract %4 %109 0 +%184 = OpFMul %4 %182 %183 +%185 = OpCompositeExtract %4 %171 0 +%186 = OpCompositeExtract %4 %109 1 +%187 = OpFMul %4 %185 %186 +%188 = OpFAdd %4 %184 %187 %189 = OpVectorShuffle %6 %174 %174 1 2 %190 = OpLoad %7 %91 %191 = OpVectorShuffle %6 %190 %190 0 2 @@ -7992,15 +7992,15 @@ OpLine %3 7172 13 %195 = OpVectorShuffle %6 %194 %194 1 3 %196 = OpFMul %6 %193 %195 %197 = OpFAdd %6 %192 %196 -%198 = OpCompositeConstruct %4 %188 %197 +%198 = OpCompositeConstruct %5 %188 %197 OpLine %3 7173 19 -%199 = OpLoad %4 %94 -%200 = OpDot %5 %199 %198 +%199 = OpLoad %5 %94 +%200 = OpDot %4 %199 %198 OpLine %3 7173 12 -%201 = OpFMul %5 %85 %200 +%201 = OpFMul %4 %85 %200 OpReturnValue %201 OpFunctionEnd -%204 = OpFunction %5 None %68 +%204 = OpFunction %4 None %68 %203 = OpFunctionParameter %6 %202 = OpLabel %214 = OpVariable %215 Function %74 @@ -8016,11 +8016,11 @@ OpStore %212 %220 OpLine %3 7182 17 OpLine %3 7183 14 OpLine %3 7184 15 -%221 = OpCompositeExtract %5 %211 0 -%222 = OpCompositeExtract %5 %211 1 -%223 = OpCompositeExtract %5 %211 1 -%224 = OpFNegate %5 %223 -%225 = OpCompositeExtract %5 %211 0 +%221 = OpCompositeExtract %4 %211 0 +%222 = OpCompositeExtract %4 %211 1 +%223 = OpCompositeExtract %4 %211 1 +%224 = OpFNegate %4 %223 +%225 = OpCompositeExtract %4 %211 0 %226 = OpCompositeConstruct %6 %221 %222 %227 = OpCompositeConstruct %6 %224 %225 %228 = OpCompositeConstruct %9 %226 %227 @@ -8042,14 +8042,14 @@ OpBranch %230 OpBranch %237 %237 = OpLabel OpLine %3 1 1 -%239 = OpLoad %5 %214 -%240 = OpLoad %5 %216 +%239 = OpLoad %4 %214 +%240 = OpLoad %4 %216 %241 = OpLoad %6 %212 OpLine %3 7187 21 -%242 = OpFunctionCall %5 %67 %241 +%242 = OpFunctionCall %4 %67 %241 OpLine %3 7187 13 -%243 = OpFMul %5 %240 %242 -%244 = OpFAdd %5 %239 %243 +%243 = OpFMul %4 %240 %242 +%244 = OpFAdd %4 %239 %243 OpLine %3 7187 9 OpStore %214 %244 OpLine %3 7188 13 @@ -8061,9 +8061,9 @@ OpLine %3 7188 13 OpLine %3 7188 9 OpStore %212 %248 OpLine %3 1 1 -%249 = OpLoad %5 %216 +%249 = OpLoad %4 %216 OpLine %3 7189 13 -%250 = OpFMul %5 %249 %78 +%250 = OpFMul %4 %249 %78 OpLine %3 7189 9 OpStore %216 %250 OpBranch %238 @@ -8079,25 +8079,25 @@ OpStore %217 %252 OpBranch %229 %230 = OpLabel OpLine %3 1 1 -%253 = OpLoad %5 %214 +%253 = OpLoad %4 %214 OpReturnValue %253 OpFunctionEnd -%257 = OpFunction %4 None %258 +%257 = OpFunction %5 None %258 %255 = OpFunctionParameter %6 %256 = OpFunctionParameter %6 %254 = OpLabel OpBranch %259 %259 = OpLabel OpLine %3 7220 9 -%260 = OpCompositeExtract %5 %255 0 -%261 = OpCompositeExtract %5 %256 0 -%262 = OpCompositeExtract %5 %256 1 +%260 = OpCompositeExtract %4 %255 0 +%261 = OpCompositeExtract %4 %256 0 +%262 = OpCompositeExtract %4 %256 1 OpLine %3 7221 49 -%263 = OpFunctionCall %5 %204 %255 +%263 = OpFunctionCall %4 %204 %255 OpLine %3 7219 12 -%264 = OpExtInst %5 %1 FMix %261 %262 %263 -%265 = OpCompositeExtract %5 %255 1 -%266 = OpCompositeConstruct %4 %260 %264 %265 +%264 = OpExtInst %4 %1 FMix %261 %262 %263 +%265 = OpCompositeExtract %4 %255 1 +%266 = OpCompositeConstruct %5 %260 %264 %265 OpReturnValue %266 OpFunctionEnd %270 = OpFunction %14 None %271 @@ -8107,41 +8107,41 @@ OpFunctionEnd OpBranch %278 %278 = OpLabel OpLine %3 7227 13 -%279 = OpFunctionCall %4 %257 %268 %269 +%279 = OpFunctionCall %5 %257 %268 %269 OpLine %3 7229 29 %280 = OpFAdd %6 %268 %273 OpLine %3 7229 15 -%281 = OpFunctionCall %4 %257 %280 %269 +%281 = OpFunctionCall %5 %257 %280 %269 OpLine %3 7229 15 -%282 = OpFSub %4 %281 %279 +%282 = OpFSub %5 %281 %279 OpLine %3 7230 29 %283 = OpFAdd %6 %268 %274 OpLine %3 7230 15 -%284 = OpFunctionCall %4 %257 %283 %269 +%284 = OpFunctionCall %5 %257 %283 %269 OpLine %3 7230 15 -%285 = OpFSub %4 %284 %279 +%285 = OpFSub %5 %284 %279 OpLine %3 7231 29 %286 = OpFAdd %6 %268 %276 OpLine %3 7231 15 -%287 = OpFunctionCall %4 %257 %286 %269 +%287 = OpFunctionCall %5 %257 %286 %269 OpLine %3 7231 15 -%288 = OpFSub %4 %287 %279 +%288 = OpFSub %5 %287 %279 OpLine %3 7232 29 %289 = OpFAdd %6 %268 %277 OpLine %3 7232 15 -%290 = OpFunctionCall %4 %257 %289 %269 +%290 = OpFunctionCall %5 %257 %289 %269 OpLine %3 7232 15 -%291 = OpFSub %4 %290 %279 +%291 = OpFSub %5 %290 %279 OpLine %3 7234 14 -%292 = OpExtInst %4 %1 Cross %285 %282 -%293 = OpExtInst %4 %1 Normalize %292 +%292 = OpExtInst %5 %1 Cross %285 %282 +%293 = OpExtInst %5 %1 Normalize %292 OpLine %3 7235 14 -%294 = OpExtInst %4 %1 Cross %291 %288 -%295 = OpExtInst %4 %1 Normalize %294 +%294 = OpExtInst %5 %1 Cross %291 %288 +%295 = OpExtInst %5 %1 Normalize %294 OpLine %3 7237 14 -%296 = OpFAdd %4 %293 %295 +%296 = OpFAdd %5 %293 %295 OpLine %3 7237 13 -%297 = OpVectorTimesScalar %4 %296 %78 +%297 = OpVectorTimesScalar %5 %296 %78 OpLine %3 7239 12 %298 = OpCompositeConstruct %14 %279 %297 OpReturnValue %298 @@ -8154,50 +8154,50 @@ OpFunctionEnd OpBranch %305 %305 = OpLabel OpLine %3 7244 9 -%306 = OpConvertUToF %5 %300 +%306 = OpConvertUToF %4 %300 %307 = OpCompositeExtract %8 %301 0 OpLine %3 7244 9 %308 = OpIAdd %8 %307 %126 -%309 = OpConvertUToF %5 %308 -%310 = OpFRem %5 %306 %309 +%309 = OpConvertUToF %4 %308 +%310 = OpFRem %4 %306 %309 %311 = OpCompositeExtract %8 %301 0 OpLine %3 7243 12 %312 = OpIAdd %8 %311 %126 %313 = OpUDiv %8 %300 %312 -%314 = OpConvertUToF %5 %313 +%314 = OpConvertUToF %4 %313 %315 = OpCompositeConstruct %6 %310 %314 %316 = OpConvertSToF %6 %302 %317 = OpFAdd %6 %315 %316 OpReturnValue %317 OpFunctionEnd -%320 = OpFunction %4 None %321 +%320 = OpFunction %5 None %321 %319 = OpFunctionParameter %6 %318 = OpLabel OpBranch %328 %328 = OpLabel OpLine %3 7413 9 -%329 = OpFunctionCall %5 %67 %319 +%329 = OpFunctionCall %4 %67 %319 OpLine %3 7413 9 -%330 = OpFMul %5 %329 %78 +%330 = OpFMul %4 %329 %78 OpLine %3 7413 9 -%331 = OpFAdd %5 %330 %78 +%331 = OpFAdd %4 %330 %78 OpLine %3 7414 17 %332 = OpFAdd %6 %319 %324 OpLine %3 7414 9 -%333 = OpFunctionCall %5 %67 %332 +%333 = OpFunctionCall %4 %67 %332 OpLine %3 7414 9 -%334 = OpFMul %5 %333 %78 +%334 = OpFMul %4 %333 %78 OpLine %3 7414 9 -%335 = OpFAdd %5 %334 %78 +%335 = OpFAdd %4 %334 %78 OpLine %3 7415 17 %336 = OpFAdd %6 %319 %327 OpLine %3 7415 9 -%337 = OpFunctionCall %5 %67 %336 +%337 = OpFunctionCall %4 %67 %336 OpLine %3 7415 9 -%338 = OpFMul %5 %337 %78 +%338 = OpFMul %4 %337 %78 OpLine %3 7412 12 -%339 = OpFAdd %5 %338 %78 -%340 = OpCompositeConstruct %4 %331 %335 %339 +%339 = OpFAdd %4 %338 %78 +%340 = OpCompositeConstruct %5 %331 %335 %339 OpReturnValue %340 OpFunctionEnd %345 = OpFunction %2 None %346 @@ -8310,14 +8310,14 @@ OpLine %3 7304 18 %422 = OpUDiv %8 %421 %351 OpLine %3 7304 13 %423 = OpUMod %8 %422 %350 -%424 = OpConvertUToF %5 %423 +%424 = OpConvertUToF %4 %423 OpLine %3 7305 19 %425 = OpIAdd %8 %408 %126 OpLine %3 7305 18 %426 = OpUDiv %8 %425 %351 OpLine %3 7305 13 %427 = OpUMod %8 %426 %350 -%428 = OpConvertUToF %5 %427 +%428 = OpConvertUToF %4 %427 OpLine %3 7306 14 %429 = OpCompositeConstruct %6 %424 %428 OpLine %3 7308 30 @@ -8327,19 +8327,19 @@ OpLine %3 7308 30 OpLine %3 7308 20 %432 = OpCompositeConstruct %7 %431 %74 %56 OpLine %3 7311 21 -%433 = OpCompositeExtract %5 %429 0 +%433 = OpCompositeExtract %4 %429 0 OpLine %3 7311 21 %435 = OpAccessChain %434 %417 %351 %436 = OpLoad %8 %435 -%437 = OpConvertUToF %5 %436 -%438 = OpFMul %5 %433 %437 -%439 = OpCompositeExtract %5 %429 1 +%437 = OpConvertUToF %4 %436 +%438 = OpFMul %4 %433 %437 +%439 = OpCompositeExtract %4 %429 1 OpLine %3 7311 17 %440 = OpAccessChain %434 %417 %351 %441 = OpLoad %8 %440 -%442 = OpConvertUToF %5 %441 -%443 = OpFMul %5 %439 %442 -%444 = OpFAdd %5 %438 %443 +%442 = OpConvertUToF %4 %441 +%443 = OpFMul %4 %439 %442 +%444 = OpFAdd %4 %438 %443 %445 = OpConvertFToU %8 %444 OpLine %3 7311 17 %446 = OpAccessChain %434 %417 %352 @@ -8368,14 +8368,14 @@ OpBranch %470 %470 = OpLabel OpLine %3 7324 17 %471 = OpCompositeExtract %6 %454 2 -%472 = OpCompositeExtract %5 %471 0 +%472 = OpCompositeExtract %4 %471 0 OpLine %3 7324 17 %473 = OpAccessChain %434 %466 %351 %474 = OpLoad %8 %473 -%475 = OpConvertUToF %5 %474 -%476 = OpFMul %5 %472 %475 +%475 = OpConvertUToF %4 %474 +%476 = OpFMul %4 %472 %475 %477 = OpCompositeExtract %6 %454 2 -%478 = OpCompositeExtract %5 %477 1 +%478 = OpCompositeExtract %4 %477 1 OpLine %3 7324 70 %479 = OpAccessChain %434 %466 %351 %480 = OpLoad %8 %479 @@ -8383,19 +8383,19 @@ OpLine %3 7324 13 %481 = OpAccessChain %434 %466 %351 %482 = OpLoad %8 %481 %483 = OpIMul %8 %480 %482 -%484 = OpConvertUToF %5 %483 -%485 = OpFMul %5 %478 %484 -%486 = OpFAdd %5 %476 %485 +%484 = OpConvertUToF %4 %483 +%485 = OpFMul %4 %478 %484 +%486 = OpFAdd %4 %476 %485 %487 = OpConvertFToU %8 %486 OpLine %3 7324 13 %488 = OpAccessChain %434 %466 %352 %489 = OpLoad %8 %488 %490 = OpIAdd %8 %487 %489 OpLine %3 7325 32 -%491 = OpConvertUToF %5 %490 +%491 = OpConvertUToF %4 %490 OpLine %3 7325 22 -%492 = OpFDiv %5 %491 %467 -%493 = OpExtInst %5 %1 Floor %492 +%492 = OpFDiv %4 %491 %467 +%493 = OpExtInst %4 %1 Floor %492 %494 = OpConvertFToU %8 %493 OpLine %3 7326 22 %495 = OpUMod %8 %490 %349 @@ -8417,43 +8417,43 @@ OpSelectionMerge %504 None OpSwitch %495 %511 0 %505 1 %506 2 %507 3 %508 4 %509 5 %510 %505 = OpLabel OpLine %3 7334 37 -%512 = OpCompositeExtract %4 %503 0 -%513 = OpCompositeExtract %5 %512 0 +%512 = OpCompositeExtract %5 %503 0 +%513 = OpCompositeExtract %4 %512 0 OpLine %3 7334 20 OpStore %468 %513 OpBranch %504 %506 = OpLabel OpLine %3 7335 37 -%514 = OpCompositeExtract %4 %503 0 -%515 = OpCompositeExtract %5 %514 1 +%514 = OpCompositeExtract %5 %503 0 +%515 = OpCompositeExtract %4 %514 1 OpLine %3 7335 20 OpStore %468 %515 OpBranch %504 %507 = OpLabel OpLine %3 7336 37 -%516 = OpCompositeExtract %4 %503 0 -%517 = OpCompositeExtract %5 %516 2 +%516 = OpCompositeExtract %5 %503 0 +%517 = OpCompositeExtract %4 %516 2 OpLine %3 7336 20 OpStore %468 %517 OpBranch %504 %508 = OpLabel OpLine %3 7337 37 -%518 = OpCompositeExtract %4 %503 1 -%519 = OpCompositeExtract %5 %518 0 +%518 = OpCompositeExtract %5 %503 1 +%519 = OpCompositeExtract %4 %518 0 OpLine %3 7337 20 OpStore %468 %519 OpBranch %504 %509 = OpLabel OpLine %3 7338 37 -%520 = OpCompositeExtract %4 %503 1 -%521 = OpCompositeExtract %5 %520 1 +%520 = OpCompositeExtract %5 %503 1 +%521 = OpCompositeExtract %4 %520 1 OpLine %3 7338 20 OpStore %468 %521 OpBranch %504 %510 = OpLabel OpLine %3 7339 37 -%522 = OpCompositeExtract %4 %503 1 -%523 = OpCompositeExtract %5 %522 2 +%522 = OpCompositeExtract %5 %503 1 +%523 = OpCompositeExtract %4 %522 2 OpLine %3 7339 20 OpStore %468 %523 OpBranch %504 @@ -8502,7 +8502,7 @@ OpLine %3 7356 13 OpLine %3 7356 5 OpStore %469 %540 OpLine %3 7365 27 -%541 = OpLoad %5 %468 +%541 = OpLoad %4 %468 %542 = OpBitcast %8 %541 OpLine %3 7366 12 %543 = OpLoad %8 %469 @@ -8515,8 +8515,8 @@ OpReturn OpFunctionEnd %558 = OpFunction %2 None %346 %547 = OpLabel -%551 = OpLoad %4 %549 -%553 = OpLoad %4 %552 +%551 = OpLoad %5 %549 +%553 = OpLoad %5 %552 %548 = OpCompositeConstruct %14 %551 %553 %560 = OpAccessChain %559 %39 %135 OpBranch %561 @@ -8524,20 +8524,20 @@ OpBranch %561 OpLine %3 7397 25 %563 = OpAccessChain %562 %560 %126 %564 = OpLoad %23 %563 -%565 = OpCompositeExtract %4 %548 0 +%565 = OpCompositeExtract %5 %548 0 OpLine %3 7397 25 %566 = OpCompositeConstruct %7 %565 %56 %567 = OpMatrixTimesVector %7 %564 %566 OpLine %3 7398 18 -%568 = OpCompositeExtract %4 %548 1 +%568 = OpCompositeExtract %5 %548 1 OpLine %3 7399 12 -%569 = OpCompositeExtract %4 %548 0 +%569 = OpCompositeExtract %5 %548 0 %570 = OpCompositeConstruct %26 %567 %568 %569 %571 = OpCompositeExtract %7 %570 0 OpStore %554 %571 -%572 = OpCompositeExtract %4 %570 1 +%572 = OpCompositeExtract %5 %570 1 OpStore %555 %572 -%573 = OpCompositeExtract %4 %570 2 +%573 = OpCompositeExtract %5 %570 2 OpStore %557 %573 OpReturn OpFunctionEnd @@ -8545,8 +8545,8 @@ OpFunctionEnd %574 = OpLabel %592 = OpVariable %95 Function %593 %577 = OpLoad %7 %576 -%579 = OpLoad %4 %578 -%581 = OpLoad %4 %580 +%579 = OpLoad %5 %578 +%581 = OpLoad %5 %580 %575 = OpCompositeConstruct %26 %577 %579 %581 %584 = OpAccessChain %559 %39 %135 %586 = OpAccessChain %585 %42 %135 @@ -8554,70 +8554,70 @@ OpBranch %594 %594 = OpLabel OpLine %3 7421 28 OpLine %3 7421 17 -%595 = OpCompositeExtract %4 %575 2 -%596 = OpExtInst %4 %1 Fract %595 -%597 = OpExtInst %4 %1 SmoothStep %80 %587 %596 +%595 = OpCompositeExtract %5 %575 2 +%596 = OpExtInst %5 %1 Fract %595 +%597 = OpExtInst %5 %1 SmoothStep %80 %587 %596 OpLine %3 7421 5 OpStore %592 %597 OpLine %3 7422 17 OpLine %3 7422 13 %598 = OpAccessChain %125 %592 %135 -%599 = OpLoad %5 %598 +%599 = OpLoad %4 %598 %600 = OpAccessChain %125 %592 %126 -%601 = OpLoad %5 %600 -%602 = OpFMul %5 %599 %601 +%601 = OpLoad %4 %600 +%602 = OpFMul %4 %599 %601 %603 = OpAccessChain %125 %592 %350 -%604 = OpLoad %5 %603 -%605 = OpFMul %5 %602 %604 -%606 = OpCompositeConstruct %4 %605 %605 %605 -%607 = OpExtInst %4 %1 FMix %589 %591 %606 +%604 = OpLoad %4 %603 +%605 = OpFMul %4 %602 %604 +%606 = OpCompositeConstruct %5 %605 %605 %605 +%607 = OpExtInst %5 %1 FMix %589 %591 %606 OpLine %3 7422 5 OpStore %592 %607 OpLine %3 7425 25 %609 = OpAccessChain %608 %586 %126 -%610 = OpLoad %4 %609 -%611 = OpVectorTimesScalar %4 %610 %272 +%610 = OpLoad %5 %609 +%611 = OpVectorTimesScalar %5 %610 %272 OpLine %3 7427 21 %612 = OpAccessChain %608 %586 %135 -%613 = OpLoad %4 %612 -%614 = OpCompositeExtract %4 %575 2 -%615 = OpFSub %4 %613 %614 -%616 = OpExtInst %4 %1 Normalize %615 +%613 = OpLoad %5 %612 +%614 = OpCompositeExtract %5 %575 2 +%615 = OpFSub %5 %613 %614 +%616 = OpExtInst %5 %1 Normalize %615 OpLine %3 7428 20 %618 = OpAccessChain %617 %584 %135 %619 = OpLoad %7 %618 -%620 = OpVectorShuffle %4 %619 %619 0 1 2 -%621 = OpCompositeExtract %4 %575 2 -%622 = OpFSub %4 %620 %621 -%623 = OpExtInst %4 %1 Normalize %622 +%620 = OpVectorShuffle %5 %619 %619 0 1 2 +%621 = OpCompositeExtract %5 %575 2 +%622 = OpFSub %5 %620 %621 +%623 = OpExtInst %5 %1 Normalize %622 OpLine %3 7429 20 -%624 = OpFAdd %4 %623 %616 -%625 = OpExtInst %4 %1 Normalize %624 +%624 = OpFAdd %5 %623 %616 +%625 = OpExtInst %5 %1 Normalize %624 OpLine %3 7431 32 -%626 = OpCompositeExtract %4 %575 1 -%627 = OpDot %5 %626 %616 +%626 = OpCompositeExtract %5 %575 1 +%627 = OpDot %4 %626 %616 OpLine %3 7431 28 -%628 = OpExtInst %5 %1 FMax %627 %74 +%628 = OpExtInst %4 %1 FMax %627 %74 OpLine %3 7432 25 %629 = OpAccessChain %608 %586 %126 -%630 = OpLoad %4 %629 -%631 = OpVectorTimesScalar %4 %630 %628 +%630 = OpLoad %5 %629 +%631 = OpVectorTimesScalar %5 %630 %628 OpLine %3 7434 37 -%632 = OpCompositeExtract %4 %575 1 -%633 = OpDot %5 %632 %625 +%632 = OpCompositeExtract %5 %575 1 +%633 = OpDot %4 %632 %625 OpLine %3 7434 33 -%634 = OpExtInst %5 %1 FMax %633 %74 +%634 = OpExtInst %4 %1 FMax %633 %74 OpLine %3 7434 29 -%635 = OpExtInst %5 %1 Pow %634 %323 +%635 = OpExtInst %4 %1 Pow %634 %323 OpLine %3 7435 26 %636 = OpAccessChain %608 %586 %126 -%637 = OpLoad %4 %636 -%638 = OpVectorTimesScalar %4 %637 %635 +%637 = OpLoad %5 %636 +%638 = OpVectorTimesScalar %5 %637 %635 OpLine %3 7437 18 -%639 = OpFAdd %4 %611 %631 -%640 = OpFAdd %4 %639 %638 -%641 = OpLoad %4 %592 -%642 = OpFMul %4 %640 %641 +%639 = OpFAdd %5 %611 %631 +%640 = OpFAdd %5 %639 %638 +%641 = OpLoad %5 %592 +%642 = OpFMul %5 %640 %641 OpLine %3 7439 12 %643 = OpCompositeConstruct %7 %642 %56 OpStore %582 %643 diff --git a/naga/tests/out/spv/debug-symbol-simple.spvasm b/naga/tests/out/spv/debug-symbol-simple.spvasm index b2fd1f2607..e525177f28 100644 --- a/naga/tests/out/spv/debug-symbol-simple.spvasm +++ b/naga/tests/out/spv/debug-symbol-simple.spvasm @@ -72,24 +72,24 @@ OpDecorate %43 BuiltIn FragCoord OpDecorate %46 Location 0 OpDecorate %48 Location 0 %2 = OpTypeVoid -%5 = OpTypeFloat 32 -%4 = OpTypeVector %5 3 -%6 = OpTypeStruct %4 %4 -%7 = OpTypeVector %5 4 -%8 = OpTypeStruct %7 %4 +%4 = OpTypeFloat 32 +%5 = OpTypeVector %4 3 +%6 = OpTypeStruct %5 %5 +%7 = OpTypeVector %4 4 +%8 = OpTypeStruct %7 %5 %9 = OpTypeInt 32 1 -%13 = OpTypePointer Input %4 +%13 = OpTypePointer Input %5 %12 = OpVariable %13 Input %15 = OpVariable %13 Input %18 = OpTypePointer Output %7 %17 = OpVariable %18 Output -%20 = OpTypePointer Output %4 +%20 = OpTypePointer Output %5 %19 = OpVariable %20 Output %22 = OpTypeFunction %2 -%23 = OpConstant %5 1.0 +%23 = OpConstant %4 1.0 %25 = OpTypePointer Function %8 %26 = OpConstantNull %8 -%28 = OpTypePointer Function %4 +%28 = OpTypePointer Function %5 %31 = OpTypeInt 32 0 %30 = OpConstant %31 1 %33 = OpTypePointer Function %7 @@ -100,30 +100,30 @@ OpDecorate %48 Location 0 %48 = OpVariable %18 Output %50 = OpConstant %9 0 %51 = OpConstant %9 10 -%52 = OpConstant %5 0.001 -%53 = OpConstant %5 0.002 +%52 = OpConstant %4 0.001 +%53 = OpConstant %4 0.002 %54 = OpConstant %9 1 -%56 = OpConstantNull %4 +%56 = OpConstantNull %5 %58 = OpTypePointer Function %9 -%60 = OpTypePointer Function %5 -%61 = OpConstantNull %5 +%60 = OpTypePointer Function %4 +%61 = OpConstantNull %4 %69 = OpTypeBool -%77 = OpTypePointer Function %5 +%77 = OpTypePointer Function %4 %21 = OpFunction %2 None %22 %10 = OpLabel %24 = OpVariable %25 Function %26 -%14 = OpLoad %4 %12 -%16 = OpLoad %4 %15 +%14 = OpLoad %5 %12 +%16 = OpLoad %5 %15 %11 = OpCompositeConstruct %6 %14 %16 OpBranch %27 %27 = OpLabel OpLine %3 16 5 -%29 = OpCompositeExtract %4 %11 1 +%29 = OpCompositeExtract %5 %11 1 OpLine %3 16 5 %32 = OpAccessChain %28 %24 %30 OpStore %32 %29 OpLine %3 17 5 -%34 = OpCompositeExtract %4 %11 0 +%34 = OpCompositeExtract %5 %11 0 OpLine %3 17 25 %35 = OpCompositeConstruct %7 %34 %23 OpLine %3 17 5 @@ -133,7 +133,7 @@ OpLine %3 1 1 %38 = OpLoad %8 %24 %39 = OpCompositeExtract %7 %38 0 OpStore %17 %39 -%40 = OpCompositeExtract %4 %38 1 +%40 = OpCompositeExtract %5 %38 1 OpStore %19 %40 OpReturn OpFunctionEnd @@ -143,12 +143,12 @@ OpFunctionEnd %57 = OpVariable %58 Function %50 %59 = OpVariable %60 Function %61 %45 = OpLoad %7 %43 -%47 = OpLoad %4 %46 +%47 = OpLoad %5 %46 %42 = OpCompositeConstruct %8 %45 %47 OpBranch %62 %62 = OpLabel OpLine %3 25 17 -%63 = OpCompositeExtract %4 %42 1 +%63 = OpCompositeExtract %5 %42 1 OpLine %3 25 5 OpStore %55 %63 OpBranch %64 @@ -171,26 +171,26 @@ OpBranch %73 %73 = OpLabel OpLine %3 27 18 %75 = OpLoad %9 %57 -%76 = OpConvertSToF %5 %75 +%76 = OpConvertSToF %4 %75 OpLine %3 27 9 OpStore %59 %76 OpLine %3 28 9 -%78 = OpLoad %5 %59 +%78 = OpLoad %4 %59 OpLine %3 28 9 -%79 = OpFMul %5 %78 %52 +%79 = OpFMul %4 %78 %52 %80 = OpAccessChain %77 %55 %36 -%81 = OpLoad %5 %80 -%82 = OpFAdd %5 %81 %79 +%81 = OpLoad %4 %80 +%82 = OpFAdd %4 %81 %79 OpLine %3 28 9 %83 = OpAccessChain %77 %55 %36 OpStore %83 %82 OpLine %3 29 9 -%84 = OpLoad %5 %59 +%84 = OpLoad %4 %59 OpLine %3 29 9 -%85 = OpFMul %5 %84 %53 +%85 = OpFMul %4 %84 %53 %86 = OpAccessChain %77 %55 %30 -%87 = OpLoad %5 %86 -%88 = OpFAdd %5 %87 %85 +%87 = OpLoad %4 %86 +%88 = OpFAdd %4 %87 %85 OpLine %3 29 9 %89 = OpAccessChain %77 %55 %30 OpStore %89 %88 @@ -206,7 +206,7 @@ OpStore %57 %91 OpBranch %64 %65 = OpLabel OpLine %3 1 1 -%92 = OpLoad %4 %55 +%92 = OpLoad %5 %55 OpLine %3 32 12 %93 = OpCompositeConstruct %7 %92 %23 OpStore %48 %93 diff --git a/naga/tests/out/spv/debug-symbol-terrain.spvasm b/naga/tests/out/spv/debug-symbol-terrain.spvasm index fd8e7f5df3..38d8984d0f 100644 --- a/naga/tests/out/spv/debug-symbol-terrain.spvasm +++ b/naga/tests/out/spv/debug-symbol-terrain.spvasm @@ -488,17 +488,17 @@ OpDecorate %578 Location 0 OpDecorate %580 Location 1 OpDecorate %582 Location 0 %2 = OpTypeVoid -%5 = OpTypeFloat 32 -%4 = OpTypeVector %5 3 -%6 = OpTypeVector %5 2 -%7 = OpTypeVector %5 4 +%4 = OpTypeFloat 32 +%5 = OpTypeVector %4 3 +%6 = OpTypeVector %4 2 +%7 = OpTypeVector %4 4 %8 = OpTypeInt 32 0 %9 = OpTypeMatrix %6 2 %10 = OpTypeVector %8 2 %12 = OpTypeInt 32 1 %11 = OpTypeVector %12 2 %13 = OpTypeStruct %10 %11 %6 -%14 = OpTypeStruct %4 %4 +%14 = OpTypeStruct %5 %5 %15 = OpTypeRuntimeArray %14 %16 = OpTypeStruct %15 %17 = OpTypeRuntimeArray %8 @@ -509,9 +509,9 @@ OpDecorate %582 Location 0 %22 = OpTypeStruct %8 %8 %23 = OpTypeMatrix %7 4 %24 = OpTypeStruct %7 %23 -%25 = OpTypeStruct %4 %4 -%26 = OpTypeStruct %7 %4 %4 -%27 = OpTypeImage %5 2D 0 0 0 1 Unknown +%25 = OpTypeStruct %5 %5 +%26 = OpTypeStruct %7 %5 %5 +%27 = OpTypeImage %4 2D 0 0 0 1 Unknown %28 = OpTypeSampler %30 = OpTypeStruct %13 %31 = OpTypePointer Uniform %30 @@ -535,67 +535,67 @@ OpDecorate %582 Location 0 %47 = OpVariable %48 UniformConstant %49 = OpVariable %46 UniformConstant %50 = OpVariable %48 UniformConstant -%54 = OpTypeFunction %4 %4 -%55 = OpConstant %5 34.0 -%56 = OpConstant %5 1.0 -%57 = OpConstantComposite %4 %56 %56 %56 -%58 = OpConstant %5 289.0 -%59 = OpConstantComposite %4 %58 %58 %58 -%68 = OpTypeFunction %5 %6 -%69 = OpConstant %5 0.21132487 -%70 = OpConstant %5 0.36602542 -%71 = OpConstant %5 -0.57735026 -%72 = OpConstant %5 0.024390243 +%54 = OpTypeFunction %5 %5 +%55 = OpConstant %4 34.0 +%56 = OpConstant %4 1.0 +%57 = OpConstantComposite %5 %56 %56 %56 +%58 = OpConstant %4 289.0 +%59 = OpConstantComposite %5 %58 %58 %58 +%68 = OpTypeFunction %4 %6 +%69 = OpConstant %4 0.21132487 +%70 = OpConstant %4 0.36602542 +%71 = OpConstant %4 -0.57735026 +%72 = OpConstant %4 0.024390243 %73 = OpConstantComposite %7 %69 %70 %71 %72 -%74 = OpConstant %5 0.0 +%74 = OpConstant %4 0.0 %75 = OpConstantComposite %6 %56 %74 %76 = OpConstantComposite %6 %74 %56 %77 = OpConstantComposite %6 %58 %58 -%78 = OpConstant %5 0.5 -%79 = OpConstantComposite %4 %78 %78 %78 -%80 = OpConstantComposite %4 %74 %74 %74 -%81 = OpConstant %5 2.0 -%82 = OpConstant %5 0.85373473 -%83 = OpConstant %5 1.7928429 -%84 = OpConstantComposite %4 %83 %83 %83 -%85 = OpConstant %5 130.0 +%78 = OpConstant %4 0.5 +%79 = OpConstantComposite %5 %78 %78 %78 +%80 = OpConstantComposite %5 %74 %74 %74 +%81 = OpConstant %4 2.0 +%82 = OpConstant %4 0.85373473 +%83 = OpConstant %4 1.7928429 +%84 = OpConstantComposite %5 %83 %83 %83 +%85 = OpConstant %4 130.0 %87 = OpTypePointer Function %6 %88 = OpConstantNull %6 %90 = OpConstantNull %6 %92 = OpTypePointer Function %7 %93 = OpConstantNull %7 -%95 = OpTypePointer Function %4 -%96 = OpConstantNull %4 +%95 = OpTypePointer Function %5 +%96 = OpConstantNull %5 %112 = OpTypeBool %115 = OpTypeVector %112 2 -%125 = OpTypePointer Function %5 +%125 = OpTypePointer Function %4 %126 = OpConstant %8 1 %135 = OpConstant %8 0 %205 = OpConstant %8 5 -%206 = OpConstant %5 0.01 -%207 = OpConstant %5 100.0 +%206 = OpConstant %4 0.01 +%207 = OpConstant %4 100.0 %208 = OpConstantComposite %6 %207 %207 -%209 = OpConstant %5 0.87758255 -%210 = OpConstant %5 0.47942555 +%209 = OpConstant %4 0.87758255 +%210 = OpConstant %4 0.47942555 %211 = OpConstantComposite %6 %209 %210 %213 = OpConstantNull %6 -%215 = OpTypePointer Function %5 +%215 = OpTypePointer Function %4 %218 = OpTypePointer Function %8 -%258 = OpTypeFunction %4 %6 %6 +%258 = OpTypeFunction %5 %6 %6 %271 = OpTypeFunction %14 %6 %6 -%272 = OpConstant %5 0.1 +%272 = OpConstant %4 0.1 %273 = OpConstantComposite %6 %272 %74 %274 = OpConstantComposite %6 %74 %272 -%275 = OpConstant %5 -0.1 +%275 = OpConstant %4 -0.1 %276 = OpConstantComposite %6 %275 %74 %277 = OpConstantComposite %6 %74 %275 %304 = OpTypeFunction %6 %8 %10 %11 -%321 = OpTypeFunction %4 %6 -%322 = OpConstant %5 23.0 -%323 = OpConstant %5 32.0 +%321 = OpTypeFunction %5 %6 +%322 = OpConstant %4 23.0 +%323 = OpConstant %4 32.0 %324 = OpConstantComposite %6 %322 %323 -%325 = OpConstant %5 -43.0 -%326 = OpConstant %5 3.0 +%325 = OpConstant %4 -43.0 +%326 = OpConstant %4 3.0 %327 = OpConstantComposite %6 %325 %326 %343 = OpTypePointer Input %19 %342 = OpVariable %343 Input @@ -622,7 +622,7 @@ OpDecorate %582 Location 0 %414 = OpTypePointer Output %6 %413 = OpVariable %414 Output %416 = OpTypePointer Uniform %20 -%418 = OpConstant %5 -1.0 +%418 = OpConstant %4 -1.0 %419 = OpConstantComposite %6 %418 %418 %434 = OpTypePointer Uniform %8 %455 = OpVariable %407 Input @@ -632,12 +632,12 @@ OpDecorate %582 Location 0 %460 = OpVariable %461 Input %463 = OpVariable %410 Output %464 = OpVariable %410 Output -%467 = OpConstant %5 6.0 -%550 = OpTypePointer Input %4 +%467 = OpConstant %4 6.0 +%550 = OpTypePointer Input %5 %549 = OpVariable %550 Input %552 = OpVariable %550 Input %554 = OpVariable %412 Output -%556 = OpTypePointer Output %4 +%556 = OpTypePointer Output %5 %555 = OpVariable %556 Output %557 = OpVariable %556 Output %559 = OpTypePointer Uniform %24 @@ -647,30 +647,30 @@ OpDecorate %582 Location 0 %580 = OpVariable %550 Input %582 = OpVariable %412 Output %585 = OpTypePointer Uniform %25 -%587 = OpConstantComposite %4 %272 %272 %272 -%588 = OpConstant %5 0.7 -%589 = OpConstantComposite %4 %78 %272 %588 -%590 = OpConstant %5 0.2 -%591 = OpConstantComposite %4 %590 %590 %590 -%593 = OpConstantNull %4 -%608 = OpTypePointer Uniform %4 +%587 = OpConstantComposite %5 %272 %272 %272 +%588 = OpConstant %4 0.7 +%589 = OpConstantComposite %5 %78 %272 %588 +%590 = OpConstant %4 0.2 +%591 = OpConstantComposite %5 %590 %590 %590 +%593 = OpConstantNull %5 +%608 = OpTypePointer Uniform %5 %617 = OpTypePointer Uniform %7 -%53 = OpFunction %4 None %54 -%52 = OpFunctionParameter %4 +%53 = OpFunction %5 None %54 +%52 = OpFunctionParameter %5 %51 = OpLabel OpBranch %60 %60 = OpLabel OpLine %3 10 52 -%61 = OpVectorTimesScalar %4 %52 %55 +%61 = OpVectorTimesScalar %5 %52 %55 OpLine %3 10 63 OpLine %3 10 50 -%62 = OpFAdd %4 %61 %57 -%63 = OpFMul %4 %62 %52 +%62 = OpFAdd %5 %61 %57 +%63 = OpFMul %5 %62 %52 OpLine %3 10 49 -%64 = OpFRem %4 %63 %59 +%64 = OpFRem %5 %63 %59 OpReturnValue %64 OpFunctionEnd -%67 = OpFunction %5 None %68 +%67 = OpFunction %4 None %68 %66 = OpFunctionParameter %6 %65 = OpLabel %89 = OpVariable %87 Function %90 @@ -682,7 +682,7 @@ OpBranch %97 OpLine %3 13 13 OpLine %3 14 24 %98 = OpVectorShuffle %6 %73 %73 1 1 -%99 = OpDot %5 %66 %98 +%99 = OpDot %4 %66 %98 %100 = OpCompositeConstruct %6 %99 %99 %101 = OpFAdd %6 %66 %100 %102 = OpExtInst %6 %1 Floor %101 @@ -693,13 +693,13 @@ OpLine %3 15 14 %104 = OpFSub %6 %66 %103 %105 = OpLoad %6 %86 %106 = OpVectorShuffle %6 %73 %73 0 0 -%107 = OpDot %5 %105 %106 +%107 = OpDot %4 %105 %106 %108 = OpCompositeConstruct %6 %107 %107 %109 = OpFAdd %6 %104 %108 OpLine %3 17 32 OpLine %3 17 25 -%110 = OpCompositeExtract %5 %109 0 -%111 = OpCompositeExtract %5 %109 1 +%110 = OpCompositeExtract %4 %109 0 +%111 = OpCompositeExtract %4 %109 1 %113 = OpFOrdLessThan %112 %110 %111 %116 = OpCompositeConstruct %115 %113 %113 %114 = OpSelect %6 %116 %76 %75 @@ -723,101 +723,101 @@ OpLine %3 19 5 OpStore %86 %124 OpLine %3 20 31 %127 = OpAccessChain %125 %86 %126 -%128 = OpLoad %5 %127 +%128 = OpLoad %4 %127 OpLine %3 20 51 %129 = OpAccessChain %125 %89 %126 -%130 = OpLoad %5 %129 +%130 = OpLoad %4 %129 OpLine %3 20 31 -%131 = OpCompositeConstruct %4 %74 %130 %56 -%132 = OpCompositeConstruct %4 %128 %128 %128 -%133 = OpFAdd %4 %132 %131 +%131 = OpCompositeConstruct %5 %74 %130 %56 +%132 = OpCompositeConstruct %5 %128 %128 %128 +%133 = OpFAdd %5 %132 %131 OpLine %3 20 22 -%134 = OpFunctionCall %4 %53 %133 +%134 = OpFunctionCall %5 %53 %133 OpLine %3 20 22 %136 = OpAccessChain %125 %86 %135 -%137 = OpLoad %5 %136 -%138 = OpCompositeConstruct %4 %137 %137 %137 -%139 = OpFAdd %4 %134 %138 +%137 = OpLoad %4 %136 +%138 = OpCompositeConstruct %5 %137 %137 %137 +%139 = OpFAdd %5 %134 %138 OpLine %3 20 84 %140 = OpAccessChain %125 %89 %135 -%141 = OpLoad %5 %140 +%141 = OpLoad %4 %140 OpLine %3 20 22 -%142 = OpCompositeConstruct %4 %74 %141 %56 -%143 = OpFAdd %4 %139 %142 +%142 = OpCompositeConstruct %5 %74 %141 %56 +%143 = OpFAdd %5 %139 %142 OpLine %3 20 13 -%144 = OpFunctionCall %4 %53 %143 +%144 = OpFunctionCall %5 %53 %143 OpLine %3 21 28 -%145 = OpDot %5 %109 %109 +%145 = OpDot %4 %109 %109 %146 = OpLoad %7 %91 %147 = OpVectorShuffle %6 %146 %146 0 1 %148 = OpLoad %7 %91 %149 = OpVectorShuffle %6 %148 %148 0 1 -%150 = OpDot %5 %147 %149 +%150 = OpDot %4 %147 %149 %151 = OpLoad %7 %91 %152 = OpVectorShuffle %6 %151 %151 2 3 %153 = OpLoad %7 %91 %154 = OpVectorShuffle %6 %153 %153 2 3 -%155 = OpDot %5 %152 %154 -%156 = OpCompositeConstruct %4 %145 %150 %155 +%155 = OpDot %4 %152 %154 +%156 = OpCompositeConstruct %5 %145 %150 %155 OpLine %3 21 28 -%157 = OpFSub %4 %79 %156 +%157 = OpFSub %5 %79 %156 OpLine %3 21 24 -%158 = OpExtInst %4 %1 FMax %157 %80 +%158 = OpExtInst %5 %1 FMax %157 %80 OpLine %3 21 5 OpStore %94 %158 OpLine %3 22 9 -%159 = OpLoad %4 %94 -%160 = OpLoad %4 %94 -%161 = OpFMul %4 %159 %160 +%159 = OpLoad %5 %94 +%160 = OpLoad %5 %94 +%161 = OpFMul %5 %159 %160 OpLine %3 22 5 OpStore %94 %161 OpLine %3 23 9 -%162 = OpLoad %4 %94 -%163 = OpLoad %4 %94 -%164 = OpFMul %4 %162 %163 +%162 = OpLoad %5 %94 +%163 = OpLoad %5 %94 +%164 = OpFMul %5 %162 %163 OpLine %3 23 5 OpStore %94 %164 OpLine %3 24 18 -%165 = OpVectorShuffle %4 %73 %73 3 3 3 -%166 = OpFMul %4 %144 %165 -%167 = OpExtInst %4 %1 Fract %166 +%165 = OpVectorShuffle %5 %73 %73 3 3 3 +%166 = OpFMul %5 %144 %165 +%167 = OpExtInst %5 %1 Fract %166 OpLine %3 24 13 -%168 = OpVectorTimesScalar %4 %167 %81 +%168 = OpVectorTimesScalar %5 %167 %81 OpLine %3 24 37 OpLine %3 24 13 -%169 = OpFSub %4 %168 %57 +%169 = OpFSub %5 %168 %57 OpLine %3 25 13 -%170 = OpExtInst %4 %1 FAbs %169 +%170 = OpExtInst %5 %1 FAbs %169 OpLine %3 25 22 OpLine %3 25 13 -%171 = OpFSub %4 %170 %79 +%171 = OpFSub %5 %170 %79 OpLine %3 26 24 OpLine %3 26 14 -%172 = OpFAdd %4 %169 %79 -%173 = OpExtInst %4 %1 Floor %172 +%172 = OpFAdd %5 %169 %79 +%173 = OpExtInst %5 %1 Floor %172 OpLine %3 27 14 -%174 = OpFSub %4 %169 %173 +%174 = OpFSub %5 %169 %173 OpLine %3 1 1 -%175 = OpLoad %4 %94 +%175 = OpLoad %5 %94 OpLine %3 28 53 -%176 = OpFMul %4 %174 %174 -%177 = OpFMul %4 %171 %171 -%178 = OpFAdd %4 %176 %177 +%176 = OpFMul %5 %174 %174 +%177 = OpFMul %5 %171 %171 +%178 = OpFAdd %5 %176 %177 OpLine %3 28 14 -%179 = OpVectorTimesScalar %4 %178 %82 +%179 = OpVectorTimesScalar %5 %178 %82 OpLine %3 28 9 -%180 = OpFSub %4 %84 %179 -%181 = OpFMul %4 %175 %180 +%180 = OpFSub %5 %84 %179 +%181 = OpFMul %5 %175 %180 OpLine %3 28 5 OpStore %94 %181 OpLine %3 29 13 -%182 = OpCompositeExtract %5 %174 0 -%183 = OpCompositeExtract %5 %109 0 -%184 = OpFMul %5 %182 %183 -%185 = OpCompositeExtract %5 %171 0 -%186 = OpCompositeExtract %5 %109 1 -%187 = OpFMul %5 %185 %186 -%188 = OpFAdd %5 %184 %187 +%182 = OpCompositeExtract %4 %174 0 +%183 = OpCompositeExtract %4 %109 0 +%184 = OpFMul %4 %182 %183 +%185 = OpCompositeExtract %4 %171 0 +%186 = OpCompositeExtract %4 %109 1 +%187 = OpFMul %4 %185 %186 +%188 = OpFAdd %4 %184 %187 %189 = OpVectorShuffle %6 %174 %174 1 2 %190 = OpLoad %7 %91 %191 = OpVectorShuffle %6 %190 %190 0 2 @@ -827,15 +827,15 @@ OpLine %3 29 13 %195 = OpVectorShuffle %6 %194 %194 1 3 %196 = OpFMul %6 %193 %195 %197 = OpFAdd %6 %192 %196 -%198 = OpCompositeConstruct %4 %188 %197 +%198 = OpCompositeConstruct %5 %188 %197 OpLine %3 30 19 -%199 = OpLoad %4 %94 -%200 = OpDot %5 %199 %198 +%199 = OpLoad %5 %94 +%200 = OpDot %4 %199 %198 OpLine %3 30 12 -%201 = OpFMul %5 %85 %200 +%201 = OpFMul %4 %85 %200 OpReturnValue %201 OpFunctionEnd -%204 = OpFunction %5 None %68 +%204 = OpFunction %4 None %68 %203 = OpFunctionParameter %6 %202 = OpLabel %214 = OpVariable %215 Function %74 @@ -851,11 +851,11 @@ OpStore %212 %220 OpLine %3 39 17 OpLine %3 40 14 OpLine %3 41 15 -%221 = OpCompositeExtract %5 %211 0 -%222 = OpCompositeExtract %5 %211 1 -%223 = OpCompositeExtract %5 %211 1 -%224 = OpFNegate %5 %223 -%225 = OpCompositeExtract %5 %211 0 +%221 = OpCompositeExtract %4 %211 0 +%222 = OpCompositeExtract %4 %211 1 +%223 = OpCompositeExtract %4 %211 1 +%224 = OpFNegate %4 %223 +%225 = OpCompositeExtract %4 %211 0 %226 = OpCompositeConstruct %6 %221 %222 %227 = OpCompositeConstruct %6 %224 %225 %228 = OpCompositeConstruct %9 %226 %227 @@ -877,14 +877,14 @@ OpBranch %230 OpBranch %237 %237 = OpLabel OpLine %3 1 1 -%239 = OpLoad %5 %214 -%240 = OpLoad %5 %216 +%239 = OpLoad %4 %214 +%240 = OpLoad %4 %216 %241 = OpLoad %6 %212 OpLine %3 44 21 -%242 = OpFunctionCall %5 %67 %241 +%242 = OpFunctionCall %4 %67 %241 OpLine %3 44 13 -%243 = OpFMul %5 %240 %242 -%244 = OpFAdd %5 %239 %243 +%243 = OpFMul %4 %240 %242 +%244 = OpFAdd %4 %239 %243 OpLine %3 44 9 OpStore %214 %244 OpLine %3 45 13 @@ -896,9 +896,9 @@ OpLine %3 45 13 OpLine %3 45 9 OpStore %212 %248 OpLine %3 1 1 -%249 = OpLoad %5 %216 +%249 = OpLoad %4 %216 OpLine %3 46 13 -%250 = OpFMul %5 %249 %78 +%250 = OpFMul %4 %249 %78 OpLine %3 46 9 OpStore %216 %250 OpBranch %238 @@ -914,25 +914,25 @@ OpStore %217 %252 OpBranch %229 %230 = OpLabel OpLine %3 1 1 -%253 = OpLoad %5 %214 +%253 = OpLoad %4 %214 OpReturnValue %253 OpFunctionEnd -%257 = OpFunction %4 None %258 +%257 = OpFunction %5 None %258 %255 = OpFunctionParameter %6 %256 = OpFunctionParameter %6 %254 = OpLabel OpBranch %259 %259 = OpLabel OpLine %3 77 9 -%260 = OpCompositeExtract %5 %255 0 -%261 = OpCompositeExtract %5 %256 0 -%262 = OpCompositeExtract %5 %256 1 +%260 = OpCompositeExtract %4 %255 0 +%261 = OpCompositeExtract %4 %256 0 +%262 = OpCompositeExtract %4 %256 1 OpLine %3 78 49 -%263 = OpFunctionCall %5 %204 %255 +%263 = OpFunctionCall %4 %204 %255 OpLine %3 76 12 -%264 = OpExtInst %5 %1 FMix %261 %262 %263 -%265 = OpCompositeExtract %5 %255 1 -%266 = OpCompositeConstruct %4 %260 %264 %265 +%264 = OpExtInst %4 %1 FMix %261 %262 %263 +%265 = OpCompositeExtract %4 %255 1 +%266 = OpCompositeConstruct %5 %260 %264 %265 OpReturnValue %266 OpFunctionEnd %270 = OpFunction %14 None %271 @@ -942,41 +942,41 @@ OpFunctionEnd OpBranch %278 %278 = OpLabel OpLine %3 84 13 -%279 = OpFunctionCall %4 %257 %268 %269 +%279 = OpFunctionCall %5 %257 %268 %269 OpLine %3 86 29 %280 = OpFAdd %6 %268 %273 OpLine %3 86 15 -%281 = OpFunctionCall %4 %257 %280 %269 +%281 = OpFunctionCall %5 %257 %280 %269 OpLine %3 86 15 -%282 = OpFSub %4 %281 %279 +%282 = OpFSub %5 %281 %279 OpLine %3 87 29 %283 = OpFAdd %6 %268 %274 OpLine %3 87 15 -%284 = OpFunctionCall %4 %257 %283 %269 +%284 = OpFunctionCall %5 %257 %283 %269 OpLine %3 87 15 -%285 = OpFSub %4 %284 %279 +%285 = OpFSub %5 %284 %279 OpLine %3 88 29 %286 = OpFAdd %6 %268 %276 OpLine %3 88 15 -%287 = OpFunctionCall %4 %257 %286 %269 +%287 = OpFunctionCall %5 %257 %286 %269 OpLine %3 88 15 -%288 = OpFSub %4 %287 %279 +%288 = OpFSub %5 %287 %279 OpLine %3 89 29 %289 = OpFAdd %6 %268 %277 OpLine %3 89 15 -%290 = OpFunctionCall %4 %257 %289 %269 +%290 = OpFunctionCall %5 %257 %289 %269 OpLine %3 89 15 -%291 = OpFSub %4 %290 %279 +%291 = OpFSub %5 %290 %279 OpLine %3 91 14 -%292 = OpExtInst %4 %1 Cross %285 %282 -%293 = OpExtInst %4 %1 Normalize %292 +%292 = OpExtInst %5 %1 Cross %285 %282 +%293 = OpExtInst %5 %1 Normalize %292 OpLine %3 92 14 -%294 = OpExtInst %4 %1 Cross %291 %288 -%295 = OpExtInst %4 %1 Normalize %294 +%294 = OpExtInst %5 %1 Cross %291 %288 +%295 = OpExtInst %5 %1 Normalize %294 OpLine %3 94 14 -%296 = OpFAdd %4 %293 %295 +%296 = OpFAdd %5 %293 %295 OpLine %3 94 13 -%297 = OpVectorTimesScalar %4 %296 %78 +%297 = OpVectorTimesScalar %5 %296 %78 OpLine %3 96 12 %298 = OpCompositeConstruct %14 %279 %297 OpReturnValue %298 @@ -989,50 +989,50 @@ OpFunctionEnd OpBranch %305 %305 = OpLabel OpLine %3 101 9 -%306 = OpConvertUToF %5 %300 +%306 = OpConvertUToF %4 %300 %307 = OpCompositeExtract %8 %301 0 OpLine %3 101 9 %308 = OpIAdd %8 %307 %126 -%309 = OpConvertUToF %5 %308 -%310 = OpFRem %5 %306 %309 +%309 = OpConvertUToF %4 %308 +%310 = OpFRem %4 %306 %309 %311 = OpCompositeExtract %8 %301 0 OpLine %3 100 12 %312 = OpIAdd %8 %311 %126 %313 = OpUDiv %8 %300 %312 -%314 = OpConvertUToF %5 %313 +%314 = OpConvertUToF %4 %313 %315 = OpCompositeConstruct %6 %310 %314 %316 = OpConvertSToF %6 %302 %317 = OpFAdd %6 %315 %316 OpReturnValue %317 OpFunctionEnd -%320 = OpFunction %4 None %321 +%320 = OpFunction %5 None %321 %319 = OpFunctionParameter %6 %318 = OpLabel OpBranch %328 %328 = OpLabel OpLine %3 270 9 -%329 = OpFunctionCall %5 %67 %319 +%329 = OpFunctionCall %4 %67 %319 OpLine %3 270 9 -%330 = OpFMul %5 %329 %78 +%330 = OpFMul %4 %329 %78 OpLine %3 270 9 -%331 = OpFAdd %5 %330 %78 +%331 = OpFAdd %4 %330 %78 OpLine %3 271 17 %332 = OpFAdd %6 %319 %324 OpLine %3 271 9 -%333 = OpFunctionCall %5 %67 %332 +%333 = OpFunctionCall %4 %67 %332 OpLine %3 271 9 -%334 = OpFMul %5 %333 %78 +%334 = OpFMul %4 %333 %78 OpLine %3 271 9 -%335 = OpFAdd %5 %334 %78 +%335 = OpFAdd %4 %334 %78 OpLine %3 272 17 %336 = OpFAdd %6 %319 %327 OpLine %3 272 9 -%337 = OpFunctionCall %5 %67 %336 +%337 = OpFunctionCall %4 %67 %336 OpLine %3 272 9 -%338 = OpFMul %5 %337 %78 +%338 = OpFMul %4 %337 %78 OpLine %3 269 12 -%339 = OpFAdd %5 %338 %78 -%340 = OpCompositeConstruct %4 %331 %335 %339 +%339 = OpFAdd %4 %338 %78 +%340 = OpCompositeConstruct %5 %331 %335 %339 OpReturnValue %340 OpFunctionEnd %345 = OpFunction %2 None %346 @@ -1145,14 +1145,14 @@ OpLine %3 161 18 %422 = OpUDiv %8 %421 %351 OpLine %3 161 13 %423 = OpUMod %8 %422 %350 -%424 = OpConvertUToF %5 %423 +%424 = OpConvertUToF %4 %423 OpLine %3 162 19 %425 = OpIAdd %8 %408 %126 OpLine %3 162 18 %426 = OpUDiv %8 %425 %351 OpLine %3 162 13 %427 = OpUMod %8 %426 %350 -%428 = OpConvertUToF %5 %427 +%428 = OpConvertUToF %4 %427 OpLine %3 163 14 %429 = OpCompositeConstruct %6 %424 %428 OpLine %3 165 30 @@ -1162,19 +1162,19 @@ OpLine %3 165 30 OpLine %3 165 20 %432 = OpCompositeConstruct %7 %431 %74 %56 OpLine %3 168 21 -%433 = OpCompositeExtract %5 %429 0 +%433 = OpCompositeExtract %4 %429 0 OpLine %3 168 21 %435 = OpAccessChain %434 %417 %351 %436 = OpLoad %8 %435 -%437 = OpConvertUToF %5 %436 -%438 = OpFMul %5 %433 %437 -%439 = OpCompositeExtract %5 %429 1 +%437 = OpConvertUToF %4 %436 +%438 = OpFMul %4 %433 %437 +%439 = OpCompositeExtract %4 %429 1 OpLine %3 168 17 %440 = OpAccessChain %434 %417 %351 %441 = OpLoad %8 %440 -%442 = OpConvertUToF %5 %441 -%443 = OpFMul %5 %439 %442 -%444 = OpFAdd %5 %438 %443 +%442 = OpConvertUToF %4 %441 +%443 = OpFMul %4 %439 %442 +%444 = OpFAdd %4 %438 %443 %445 = OpConvertFToU %8 %444 OpLine %3 168 17 %446 = OpAccessChain %434 %417 %352 @@ -1203,14 +1203,14 @@ OpBranch %470 %470 = OpLabel OpLine %3 181 17 %471 = OpCompositeExtract %6 %454 2 -%472 = OpCompositeExtract %5 %471 0 +%472 = OpCompositeExtract %4 %471 0 OpLine %3 181 17 %473 = OpAccessChain %434 %466 %351 %474 = OpLoad %8 %473 -%475 = OpConvertUToF %5 %474 -%476 = OpFMul %5 %472 %475 +%475 = OpConvertUToF %4 %474 +%476 = OpFMul %4 %472 %475 %477 = OpCompositeExtract %6 %454 2 -%478 = OpCompositeExtract %5 %477 1 +%478 = OpCompositeExtract %4 %477 1 OpLine %3 181 70 %479 = OpAccessChain %434 %466 %351 %480 = OpLoad %8 %479 @@ -1218,19 +1218,19 @@ OpLine %3 181 13 %481 = OpAccessChain %434 %466 %351 %482 = OpLoad %8 %481 %483 = OpIMul %8 %480 %482 -%484 = OpConvertUToF %5 %483 -%485 = OpFMul %5 %478 %484 -%486 = OpFAdd %5 %476 %485 +%484 = OpConvertUToF %4 %483 +%485 = OpFMul %4 %478 %484 +%486 = OpFAdd %4 %476 %485 %487 = OpConvertFToU %8 %486 OpLine %3 181 13 %488 = OpAccessChain %434 %466 %352 %489 = OpLoad %8 %488 %490 = OpIAdd %8 %487 %489 OpLine %3 182 32 -%491 = OpConvertUToF %5 %490 +%491 = OpConvertUToF %4 %490 OpLine %3 182 22 -%492 = OpFDiv %5 %491 %467 -%493 = OpExtInst %5 %1 Floor %492 +%492 = OpFDiv %4 %491 %467 +%493 = OpExtInst %4 %1 Floor %492 %494 = OpConvertFToU %8 %493 OpLine %3 183 22 %495 = OpUMod %8 %490 %349 @@ -1252,43 +1252,43 @@ OpSelectionMerge %504 None OpSwitch %495 %511 0 %505 1 %506 2 %507 3 %508 4 %509 5 %510 %505 = OpLabel OpLine %3 191 37 -%512 = OpCompositeExtract %4 %503 0 -%513 = OpCompositeExtract %5 %512 0 +%512 = OpCompositeExtract %5 %503 0 +%513 = OpCompositeExtract %4 %512 0 OpLine %3 191 20 OpStore %468 %513 OpBranch %504 %506 = OpLabel OpLine %3 192 37 -%514 = OpCompositeExtract %4 %503 0 -%515 = OpCompositeExtract %5 %514 1 +%514 = OpCompositeExtract %5 %503 0 +%515 = OpCompositeExtract %4 %514 1 OpLine %3 192 20 OpStore %468 %515 OpBranch %504 %507 = OpLabel OpLine %3 193 37 -%516 = OpCompositeExtract %4 %503 0 -%517 = OpCompositeExtract %5 %516 2 +%516 = OpCompositeExtract %5 %503 0 +%517 = OpCompositeExtract %4 %516 2 OpLine %3 193 20 OpStore %468 %517 OpBranch %504 %508 = OpLabel OpLine %3 194 37 -%518 = OpCompositeExtract %4 %503 1 -%519 = OpCompositeExtract %5 %518 0 +%518 = OpCompositeExtract %5 %503 1 +%519 = OpCompositeExtract %4 %518 0 OpLine %3 194 20 OpStore %468 %519 OpBranch %504 %509 = OpLabel OpLine %3 195 37 -%520 = OpCompositeExtract %4 %503 1 -%521 = OpCompositeExtract %5 %520 1 +%520 = OpCompositeExtract %5 %503 1 +%521 = OpCompositeExtract %4 %520 1 OpLine %3 195 20 OpStore %468 %521 OpBranch %504 %510 = OpLabel OpLine %3 196 37 -%522 = OpCompositeExtract %4 %503 1 -%523 = OpCompositeExtract %5 %522 2 +%522 = OpCompositeExtract %5 %503 1 +%523 = OpCompositeExtract %4 %522 2 OpLine %3 196 20 OpStore %468 %523 OpBranch %504 @@ -1337,7 +1337,7 @@ OpLine %3 213 13 OpLine %3 213 5 OpStore %469 %540 OpLine %3 222 27 -%541 = OpLoad %5 %468 +%541 = OpLoad %4 %468 %542 = OpBitcast %8 %541 OpLine %3 223 12 %543 = OpLoad %8 %469 @@ -1350,8 +1350,8 @@ OpReturn OpFunctionEnd %558 = OpFunction %2 None %346 %547 = OpLabel -%551 = OpLoad %4 %549 -%553 = OpLoad %4 %552 +%551 = OpLoad %5 %549 +%553 = OpLoad %5 %552 %548 = OpCompositeConstruct %14 %551 %553 %560 = OpAccessChain %559 %39 %135 OpBranch %561 @@ -1359,20 +1359,20 @@ OpBranch %561 OpLine %3 254 25 %563 = OpAccessChain %562 %560 %126 %564 = OpLoad %23 %563 -%565 = OpCompositeExtract %4 %548 0 +%565 = OpCompositeExtract %5 %548 0 OpLine %3 254 25 %566 = OpCompositeConstruct %7 %565 %56 %567 = OpMatrixTimesVector %7 %564 %566 OpLine %3 255 18 -%568 = OpCompositeExtract %4 %548 1 +%568 = OpCompositeExtract %5 %548 1 OpLine %3 256 12 -%569 = OpCompositeExtract %4 %548 0 +%569 = OpCompositeExtract %5 %548 0 %570 = OpCompositeConstruct %26 %567 %568 %569 %571 = OpCompositeExtract %7 %570 0 OpStore %554 %571 -%572 = OpCompositeExtract %4 %570 1 +%572 = OpCompositeExtract %5 %570 1 OpStore %555 %572 -%573 = OpCompositeExtract %4 %570 2 +%573 = OpCompositeExtract %5 %570 2 OpStore %557 %573 OpReturn OpFunctionEnd @@ -1380,8 +1380,8 @@ OpFunctionEnd %574 = OpLabel %592 = OpVariable %95 Function %593 %577 = OpLoad %7 %576 -%579 = OpLoad %4 %578 -%581 = OpLoad %4 %580 +%579 = OpLoad %5 %578 +%581 = OpLoad %5 %580 %575 = OpCompositeConstruct %26 %577 %579 %581 %584 = OpAccessChain %559 %39 %135 %586 = OpAccessChain %585 %42 %135 @@ -1389,70 +1389,70 @@ OpBranch %594 %594 = OpLabel OpLine %3 278 28 OpLine %3 278 17 -%595 = OpCompositeExtract %4 %575 2 -%596 = OpExtInst %4 %1 Fract %595 -%597 = OpExtInst %4 %1 SmoothStep %80 %587 %596 +%595 = OpCompositeExtract %5 %575 2 +%596 = OpExtInst %5 %1 Fract %595 +%597 = OpExtInst %5 %1 SmoothStep %80 %587 %596 OpLine %3 278 5 OpStore %592 %597 OpLine %3 279 17 OpLine %3 279 13 %598 = OpAccessChain %125 %592 %135 -%599 = OpLoad %5 %598 +%599 = OpLoad %4 %598 %600 = OpAccessChain %125 %592 %126 -%601 = OpLoad %5 %600 -%602 = OpFMul %5 %599 %601 +%601 = OpLoad %4 %600 +%602 = OpFMul %4 %599 %601 %603 = OpAccessChain %125 %592 %350 -%604 = OpLoad %5 %603 -%605 = OpFMul %5 %602 %604 -%606 = OpCompositeConstruct %4 %605 %605 %605 -%607 = OpExtInst %4 %1 FMix %589 %591 %606 +%604 = OpLoad %4 %603 +%605 = OpFMul %4 %602 %604 +%606 = OpCompositeConstruct %5 %605 %605 %605 +%607 = OpExtInst %5 %1 FMix %589 %591 %606 OpLine %3 279 5 OpStore %592 %607 OpLine %3 282 25 %609 = OpAccessChain %608 %586 %126 -%610 = OpLoad %4 %609 -%611 = OpVectorTimesScalar %4 %610 %272 +%610 = OpLoad %5 %609 +%611 = OpVectorTimesScalar %5 %610 %272 OpLine %3 284 21 %612 = OpAccessChain %608 %586 %135 -%613 = OpLoad %4 %612 -%614 = OpCompositeExtract %4 %575 2 -%615 = OpFSub %4 %613 %614 -%616 = OpExtInst %4 %1 Normalize %615 +%613 = OpLoad %5 %612 +%614 = OpCompositeExtract %5 %575 2 +%615 = OpFSub %5 %613 %614 +%616 = OpExtInst %5 %1 Normalize %615 OpLine %3 285 20 %618 = OpAccessChain %617 %584 %135 %619 = OpLoad %7 %618 -%620 = OpVectorShuffle %4 %619 %619 0 1 2 -%621 = OpCompositeExtract %4 %575 2 -%622 = OpFSub %4 %620 %621 -%623 = OpExtInst %4 %1 Normalize %622 +%620 = OpVectorShuffle %5 %619 %619 0 1 2 +%621 = OpCompositeExtract %5 %575 2 +%622 = OpFSub %5 %620 %621 +%623 = OpExtInst %5 %1 Normalize %622 OpLine %3 286 20 -%624 = OpFAdd %4 %623 %616 -%625 = OpExtInst %4 %1 Normalize %624 +%624 = OpFAdd %5 %623 %616 +%625 = OpExtInst %5 %1 Normalize %624 OpLine %3 288 32 -%626 = OpCompositeExtract %4 %575 1 -%627 = OpDot %5 %626 %616 +%626 = OpCompositeExtract %5 %575 1 +%627 = OpDot %4 %626 %616 OpLine %3 288 28 -%628 = OpExtInst %5 %1 FMax %627 %74 +%628 = OpExtInst %4 %1 FMax %627 %74 OpLine %3 289 25 %629 = OpAccessChain %608 %586 %126 -%630 = OpLoad %4 %629 -%631 = OpVectorTimesScalar %4 %630 %628 +%630 = OpLoad %5 %629 +%631 = OpVectorTimesScalar %5 %630 %628 OpLine %3 291 37 -%632 = OpCompositeExtract %4 %575 1 -%633 = OpDot %5 %632 %625 +%632 = OpCompositeExtract %5 %575 1 +%633 = OpDot %4 %632 %625 OpLine %3 291 33 -%634 = OpExtInst %5 %1 FMax %633 %74 +%634 = OpExtInst %4 %1 FMax %633 %74 OpLine %3 291 29 -%635 = OpExtInst %5 %1 Pow %634 %323 +%635 = OpExtInst %4 %1 Pow %634 %323 OpLine %3 292 26 %636 = OpAccessChain %608 %586 %126 -%637 = OpLoad %4 %636 -%638 = OpVectorTimesScalar %4 %637 %635 +%637 = OpLoad %5 %636 +%638 = OpVectorTimesScalar %5 %637 %635 OpLine %3 294 18 -%639 = OpFAdd %4 %611 %631 -%640 = OpFAdd %4 %639 %638 -%641 = OpLoad %4 %592 -%642 = OpFMul %4 %640 %641 +%639 = OpFAdd %5 %611 %631 +%640 = OpFAdd %5 %639 %638 +%641 = OpLoad %5 %592 +%642 = OpFMul %5 %640 %641 OpLine %3 296 12 %643 = OpCompositeConstruct %7 %642 %56 OpStore %582 %643 diff --git a/naga/tests/out/spv/fragment-output.spvasm b/naga/tests/out/spv/fragment-output.spvasm index c61ffb8258..414c646c73 100644 --- a/naga/tests/out/spv/fragment-output.spvasm +++ b/naga/tests/out/spv/fragment-output.spvasm @@ -34,25 +34,25 @@ OpDecorate %76 Location 3 OpDecorate %78 Location 4 OpDecorate %80 Location 5 %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 -%6 = OpTypeInt 32 1 -%5 = OpTypeVector %6 4 -%8 = OpTypeInt 32 0 -%7 = OpTypeVector %8 4 -%9 = OpTypeVector %4 3 -%10 = OpTypeVector %6 3 -%11 = OpTypeVector %8 3 -%12 = OpTypeStruct %3 %5 %7 %9 %10 %11 -%13 = OpTypeVector %4 2 -%14 = OpTypeVector %6 2 -%15 = OpTypeVector %8 2 -%16 = OpTypeStruct %13 %14 %15 %4 %6 %8 -%19 = OpTypePointer Output %3 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 +%5 = OpTypeInt 32 1 +%6 = OpTypeVector %5 4 +%7 = OpTypeInt 32 0 +%8 = OpTypeVector %7 4 +%9 = OpTypeVector %3 3 +%10 = OpTypeVector %5 3 +%11 = OpTypeVector %7 3 +%12 = OpTypeStruct %4 %6 %8 %9 %10 %11 +%13 = OpTypeVector %3 2 +%14 = OpTypeVector %5 2 +%15 = OpTypeVector %7 2 +%16 = OpTypeStruct %13 %14 %15 %3 %5 %7 +%19 = OpTypePointer Output %4 %18 = OpVariable %19 Output -%21 = OpTypePointer Output %5 +%21 = OpTypePointer Output %6 %20 = OpVariable %21 Output -%23 = OpTypePointer Output %7 +%23 = OpTypePointer Output %8 %22 = OpVariable %23 Output %25 = OpTypePointer Output %9 %24 = OpVariable %25 Output @@ -61,39 +61,39 @@ OpDecorate %80 Location 5 %29 = OpTypePointer Output %11 %28 = OpVariable %29 Output %31 = OpTypeFunction %2 -%32 = OpConstant %4 0.0 -%33 = OpConstantComposite %3 %32 %32 %32 %32 -%34 = OpConstant %6 0 -%35 = OpConstantComposite %5 %34 %34 %34 %34 -%36 = OpConstant %8 0 -%37 = OpConstantComposite %7 %36 %36 %36 %36 +%32 = OpConstant %3 0.0 +%33 = OpConstantComposite %4 %32 %32 %32 %32 +%34 = OpConstant %5 0 +%35 = OpConstantComposite %6 %34 %34 %34 %34 +%36 = OpConstant %7 0 +%37 = OpConstantComposite %8 %36 %36 %36 %36 %38 = OpConstantComposite %9 %32 %32 %32 %39 = OpConstantComposite %10 %34 %34 %34 %40 = OpConstantComposite %11 %36 %36 %36 %42 = OpTypePointer Function %12 %43 = OpConstantNull %12 -%45 = OpTypePointer Function %3 -%47 = OpTypePointer Function %5 -%48 = OpConstant %8 1 -%50 = OpTypePointer Function %7 -%51 = OpConstant %8 2 +%45 = OpTypePointer Function %4 +%47 = OpTypePointer Function %6 +%48 = OpConstant %7 1 +%50 = OpTypePointer Function %8 +%51 = OpConstant %7 2 %53 = OpTypePointer Function %9 -%54 = OpConstant %8 3 +%54 = OpConstant %7 3 %56 = OpTypePointer Function %10 -%57 = OpConstant %8 4 +%57 = OpConstant %7 4 %59 = OpTypePointer Function %11 -%60 = OpConstant %8 5 +%60 = OpConstant %7 5 %71 = OpTypePointer Output %13 %70 = OpVariable %71 Output %73 = OpTypePointer Output %14 %72 = OpVariable %73 Output %75 = OpTypePointer Output %15 %74 = OpVariable %75 Output -%77 = OpTypePointer Output %4 +%77 = OpTypePointer Output %3 %76 = OpVariable %77 Output -%79 = OpTypePointer Output %6 +%79 = OpTypePointer Output %5 %78 = OpVariable %79 Output -%81 = OpTypePointer Output %8 +%81 = OpTypePointer Output %7 %80 = OpVariable %81 Output %83 = OpConstantComposite %13 %32 %32 %84 = OpConstantComposite %14 %34 %34 @@ -103,9 +103,9 @@ OpDecorate %80 Location 5 %90 = OpTypePointer Function %13 %92 = OpTypePointer Function %14 %94 = OpTypePointer Function %15 -%96 = OpTypePointer Function %4 -%98 = OpTypePointer Function %6 -%100 = OpTypePointer Function %8 +%96 = OpTypePointer Function %3 +%98 = OpTypePointer Function %5 +%100 = OpTypePointer Function %7 %30 = OpFunction %2 None %31 %17 = OpLabel %41 = OpVariable %42 Function %43 @@ -124,11 +124,11 @@ OpStore %58 %39 %61 = OpAccessChain %59 %41 %60 OpStore %61 %40 %62 = OpLoad %12 %41 -%63 = OpCompositeExtract %3 %62 0 +%63 = OpCompositeExtract %4 %62 0 OpStore %18 %63 -%64 = OpCompositeExtract %5 %62 1 +%64 = OpCompositeExtract %6 %62 1 OpStore %20 %64 -%65 = OpCompositeExtract %7 %62 2 +%65 = OpCompositeExtract %8 %62 2 OpStore %22 %65 %66 = OpCompositeExtract %9 %62 3 OpStore %24 %66 @@ -162,11 +162,11 @@ OpStore %70 %103 OpStore %72 %104 %105 = OpCompositeExtract %15 %102 2 OpStore %74 %105 -%106 = OpCompositeExtract %4 %102 3 +%106 = OpCompositeExtract %3 %102 3 OpStore %76 %106 -%107 = OpCompositeExtract %6 %102 4 +%107 = OpCompositeExtract %5 %102 4 OpStore %78 %107 -%108 = OpCompositeExtract %8 %102 5 +%108 = OpCompositeExtract %7 %102 5 OpStore %80 %108 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/interface.compute.spvasm b/naga/tests/out/spv/interface.compute.spvasm index 73f6ecb2c2..912d28d5b0 100644 --- a/naga/tests/out/spv/interface.compute.spvasm +++ b/naga/tests/out/spv/interface.compute.spvasm @@ -21,11 +21,11 @@ OpDecorate %22 BuiltIn LocalInvocationIndex OpDecorate %25 BuiltIn WorkgroupId OpDecorate %27 BuiltIn NumWorkgroups %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 -%5 = OpTypeStruct %3 %4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 +%5 = OpTypeStruct %4 %3 %6 = OpTypeInt 32 0 -%7 = OpTypeStruct %4 %6 %4 +%7 = OpTypeStruct %3 %6 %3 %8 = OpTypeBool %10 = OpConstant %6 1 %9 = OpTypeArray %6 %10 diff --git a/naga/tests/out/spv/interface.fragment.spvasm b/naga/tests/out/spv/interface.fragment.spvasm index bb42c678ec..891b10d863 100644 --- a/naga/tests/out/spv/interface.fragment.spvasm +++ b/naga/tests/out/spv/interface.fragment.spvasm @@ -30,38 +30,38 @@ OpDecorate %30 BuiltIn FragDepth OpDecorate %32 BuiltIn SampleMask OpDecorate %34 Location 0 %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 -%5 = OpTypeStruct %3 %4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 +%5 = OpTypeStruct %4 %3 %6 = OpTypeInt 32 0 -%7 = OpTypeStruct %4 %6 %4 +%7 = OpTypeStruct %3 %6 %3 %8 = OpTypeBool %10 = OpConstant %6 1 %9 = OpTypeArray %6 %10 %11 = OpTypeVector %6 3 %12 = OpTypeStruct %6 %13 = OpTypeStruct %6 -%17 = OpTypePointer Input %3 +%17 = OpTypePointer Input %4 %16 = OpVariable %17 Input -%20 = OpTypePointer Input %4 +%20 = OpTypePointer Input %3 %19 = OpVariable %20 Input %23 = OpTypePointer Input %8 %22 = OpVariable %23 Input %26 = OpTypePointer Input %6 %25 = OpVariable %26 Input %28 = OpVariable %26 Input -%31 = OpTypePointer Output %4 +%31 = OpTypePointer Output %3 %30 = OpVariable %31 Output %33 = OpTypePointer Output %6 %32 = OpVariable %33 Output %34 = OpVariable %31 Output %36 = OpTypeFunction %2 -%37 = OpConstant %4 0.0 -%38 = OpConstant %4 1.0 +%37 = OpConstant %3 0.0 +%38 = OpConstant %3 1.0 %35 = OpFunction %2 None %36 %14 = OpLabel -%18 = OpLoad %3 %16 -%21 = OpLoad %4 %19 +%18 = OpLoad %4 %16 +%21 = OpLoad %3 %19 %15 = OpCompositeConstruct %5 %18 %21 %24 = OpLoad %8 %22 %27 = OpLoad %6 %25 @@ -70,17 +70,17 @@ OpBranch %39 %39 = OpLabel %40 = OpShiftLeftLogical %6 %10 %27 %41 = OpBitwiseAnd %6 %29 %40 -%42 = OpSelect %4 %24 %38 %37 -%43 = OpCompositeExtract %4 %15 1 +%42 = OpSelect %3 %24 %38 %37 +%43 = OpCompositeExtract %3 %15 1 %44 = OpCompositeConstruct %7 %43 %41 %42 -%45 = OpCompositeExtract %4 %44 0 +%45 = OpCompositeExtract %3 %44 0 OpStore %30 %45 -%46 = OpLoad %4 %30 -%47 = OpExtInst %4 %1 FClamp %46 %37 %38 +%46 = OpLoad %3 %30 +%47 = OpExtInst %3 %1 FClamp %46 %37 %38 OpStore %30 %47 %48 = OpCompositeExtract %6 %44 1 OpStore %32 %48 -%49 = OpCompositeExtract %4 %44 2 +%49 = OpCompositeExtract %3 %44 2 OpStore %34 %49 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/interface.vertex.spvasm b/naga/tests/out/spv/interface.vertex.spvasm index eaa947f5b3..93cd5adedd 100644 --- a/naga/tests/out/spv/interface.vertex.spvasm +++ b/naga/tests/out/spv/interface.vertex.spvasm @@ -22,11 +22,11 @@ OpDecorate %22 BuiltIn Position OpDecorate %24 Location 1 OpDecorate %26 BuiltIn PointSize %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 -%5 = OpTypeStruct %3 %4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 +%5 = OpTypeStruct %4 %3 %6 = OpTypeInt 32 0 -%7 = OpTypeStruct %4 %6 %4 +%7 = OpTypeStruct %3 %6 %3 %8 = OpTypeBool %10 = OpConstant %6 1 %9 = OpTypeArray %6 %10 @@ -37,15 +37,15 @@ OpDecorate %26 BuiltIn PointSize %15 = OpVariable %16 Input %18 = OpVariable %16 Input %20 = OpVariable %16 Input -%23 = OpTypePointer Output %3 +%23 = OpTypePointer Output %4 %22 = OpVariable %23 Output -%25 = OpTypePointer Output %4 +%25 = OpTypePointer Output %3 %24 = OpVariable %25 Output -%27 = OpTypePointer Output %4 +%27 = OpTypePointer Output %3 %26 = OpVariable %27 Output -%28 = OpConstant %4 1.0 +%28 = OpConstant %3 1.0 %30 = OpTypeFunction %2 -%31 = OpConstantComposite %3 %28 %28 %28 %28 +%31 = OpConstantComposite %4 %28 %28 %28 %28 %29 = OpFunction %2 None %30 %14 = OpLabel %17 = OpLoad %6 %15 @@ -56,11 +56,11 @@ OpBranch %32 %32 = OpLabel %33 = OpIAdd %6 %17 %19 %34 = OpIAdd %6 %33 %21 -%35 = OpConvertUToF %4 %34 +%35 = OpConvertUToF %3 %34 %36 = OpCompositeConstruct %5 %31 %35 -%37 = OpCompositeExtract %3 %36 0 +%37 = OpCompositeExtract %4 %36 0 OpStore %22 %37 -%38 = OpCompositeExtract %4 %36 1 +%38 = OpCompositeExtract %3 %36 1 OpStore %24 %38 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/interface.vertex_two_structs.spvasm b/naga/tests/out/spv/interface.vertex_two_structs.spvasm index bcc4aab4e5..cad89cc551 100644 --- a/naga/tests/out/spv/interface.vertex_two_structs.spvasm +++ b/naga/tests/out/spv/interface.vertex_two_structs.spvasm @@ -20,11 +20,11 @@ OpDecorate %22 Invariant OpDecorate %22 BuiltIn Position OpDecorate %24 BuiltIn PointSize %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 -%5 = OpTypeStruct %3 %4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 +%5 = OpTypeStruct %4 %3 %6 = OpTypeInt 32 0 -%7 = OpTypeStruct %4 %6 %4 +%7 = OpTypeStruct %3 %6 %3 %8 = OpTypeBool %10 = OpConstant %6 1 %9 = OpTypeArray %6 %10 @@ -34,14 +34,14 @@ OpDecorate %24 BuiltIn PointSize %17 = OpTypePointer Input %6 %16 = OpVariable %17 Input %20 = OpVariable %17 Input -%23 = OpTypePointer Output %3 +%23 = OpTypePointer Output %4 %22 = OpVariable %23 Output -%25 = OpTypePointer Output %4 +%25 = OpTypePointer Output %3 %24 = OpVariable %25 Output -%26 = OpConstant %4 1.0 +%26 = OpConstant %3 1.0 %28 = OpTypeFunction %2 %29 = OpConstant %6 2 -%30 = OpConstant %4 0.0 +%30 = OpConstant %3 0.0 %32 = OpTypePointer Function %6 %27 = OpFunction %2 None %28 %14 = OpLabel @@ -54,12 +54,12 @@ OpStore %24 %26 OpBranch %33 %33 = OpLabel %34 = OpCompositeExtract %6 %15 0 -%35 = OpConvertUToF %4 %34 +%35 = OpConvertUToF %3 %34 %36 = OpCompositeExtract %6 %19 0 -%37 = OpConvertUToF %4 %36 +%37 = OpConvertUToF %3 %36 %38 = OpLoad %6 %31 -%39 = OpConvertUToF %4 %38 -%40 = OpCompositeConstruct %3 %35 %37 %39 %30 +%39 = OpConvertUToF %3 %38 +%40 = OpCompositeConstruct %4 %35 %37 %39 %30 OpStore %22 %40 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/interpolate.spvasm b/naga/tests/out/spv/interpolate.spvasm index d2a67a9fd2..f40c257408 100644 --- a/naga/tests/out/spv/interpolate.spvasm +++ b/naga/tests/out/spv/interpolate.spvasm @@ -1,213 +1,279 @@ ; SPIR-V ; Version: 1.0 ; Generator: rspirv -; Bound: 111 +; Bound: 139 OpCapability Shader OpCapability SampleRateShading %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %26 "vert_main" %10 %12 %14 %16 %18 %20 %21 %22 %23 -OpEntryPoint Fragment %109 "frag_main" %88 %91 %94 %97 %100 %103 %105 %107 -OpExecutionMode %109 OriginUpperLeft +OpEntryPoint Vertex %30 "vert_main" %10 %12 %14 %15 %16 %18 %20 %22 %23 %24 %25 %26 %27 +OpEntryPoint Fragment %137 "frag_main" %108 %111 %114 %116 %118 %121 %124 %127 %129 %131 %133 %135 +OpExecutionMode %137 OriginUpperLeft OpMemberName %8 0 "position" OpMemberName %8 1 "_flat" -OpMemberName %8 2 "_linear" -OpMemberName %8 3 "linear_centroid" -OpMemberName %8 4 "linear_sample" -OpMemberName %8 5 "perspective" -OpMemberName %8 6 "perspective_centroid" -OpMemberName %8 7 "perspective_sample" +OpMemberName %8 2 "flat_first" +OpMemberName %8 3 "flat_either" +OpMemberName %8 4 "_linear" +OpMemberName %8 5 "linear_centroid" +OpMemberName %8 6 "linear_sample" +OpMemberName %8 7 "linear_center" +OpMemberName %8 8 "perspective" +OpMemberName %8 9 "perspective_centroid" +OpMemberName %8 10 "perspective_sample" +OpMemberName %8 11 "perspective_center" OpName %8 "FragmentInput" OpName %10 "position" OpName %12 "_flat" -OpName %14 "_linear" -OpName %16 "linear_centroid" -OpName %18 "linear_sample" -OpName %20 "perspective" -OpName %21 "perspective_centroid" -OpName %22 "perspective_sample" -OpName %26 "vert_main" -OpName %49 "out" -OpName %88 "position" -OpName %91 "_flat" -OpName %94 "_linear" -OpName %97 "linear_centroid" -OpName %100 "linear_sample" -OpName %103 "perspective" -OpName %105 "perspective_centroid" -OpName %107 "perspective_sample" -OpName %109 "frag_main" +OpName %14 "flat_first" +OpName %15 "flat_either" +OpName %16 "_linear" +OpName %18 "linear_centroid" +OpName %20 "linear_sample" +OpName %22 "linear_center" +OpName %23 "perspective" +OpName %24 "perspective_centroid" +OpName %25 "perspective_sample" +OpName %26 "perspective_center" +OpName %30 "vert_main" +OpName %60 "out" +OpName %108 "position" +OpName %111 "_flat" +OpName %114 "flat_first" +OpName %116 "flat_either" +OpName %118 "_linear" +OpName %121 "linear_centroid" +OpName %124 "linear_sample" +OpName %127 "linear_center" +OpName %129 "perspective" +OpName %131 "perspective_centroid" +OpName %133 "perspective_sample" +OpName %135 "perspective_center" +OpName %137 "frag_main" OpMemberDecorate %8 0 Offset 0 OpMemberDecorate %8 1 Offset 16 OpMemberDecorate %8 2 Offset 20 OpMemberDecorate %8 3 Offset 24 -OpMemberDecorate %8 4 Offset 32 -OpMemberDecorate %8 5 Offset 48 -OpMemberDecorate %8 6 Offset 64 -OpMemberDecorate %8 7 Offset 68 +OpMemberDecorate %8 4 Offset 28 +OpMemberDecorate %8 5 Offset 32 +OpMemberDecorate %8 6 Offset 48 +OpMemberDecorate %8 7 Offset 64 +OpMemberDecorate %8 8 Offset 80 +OpMemberDecorate %8 9 Offset 96 +OpMemberDecorate %8 10 Offset 100 +OpMemberDecorate %8 11 Offset 104 OpDecorate %10 BuiltIn Position OpDecorate %12 Location 0 OpDecorate %12 Flat OpDecorate %14 Location 1 -OpDecorate %14 NoPerspective -OpDecorate %16 Location 2 +OpDecorate %14 Flat +OpDecorate %15 Location 2 +OpDecorate %15 Flat +OpDecorate %16 Location 3 OpDecorate %16 NoPerspective -OpDecorate %16 Centroid -OpDecorate %18 Location 3 +OpDecorate %18 Location 4 OpDecorate %18 NoPerspective -OpDecorate %18 Sample -OpDecorate %20 Location 4 -OpDecorate %21 Location 5 -OpDecorate %21 Centroid -OpDecorate %22 Location 6 -OpDecorate %22 Sample -OpDecorate %23 BuiltIn PointSize -OpDecorate %88 BuiltIn FragCoord -OpDecorate %91 Location 0 -OpDecorate %91 Flat -OpDecorate %94 Location 1 -OpDecorate %94 NoPerspective -OpDecorate %97 Location 2 -OpDecorate %97 NoPerspective -OpDecorate %97 Centroid -OpDecorate %100 Location 3 -OpDecorate %100 NoPerspective -OpDecorate %100 Sample -OpDecorate %103 Location 4 -OpDecorate %105 Location 5 -OpDecorate %105 Centroid -OpDecorate %107 Location 6 -OpDecorate %107 Sample +OpDecorate %18 Centroid +OpDecorate %20 Location 6 +OpDecorate %20 NoPerspective +OpDecorate %20 Sample +OpDecorate %22 Location 7 +OpDecorate %22 NoPerspective +OpDecorate %23 Location 8 +OpDecorate %24 Location 9 +OpDecorate %24 Centroid +OpDecorate %25 Location 10 +OpDecorate %25 Sample +OpDecorate %26 Location 11 +OpDecorate %27 BuiltIn PointSize +OpDecorate %108 BuiltIn FragCoord +OpDecorate %111 Location 0 +OpDecorate %111 Flat +OpDecorate %114 Location 1 +OpDecorate %114 Flat +OpDecorate %116 Location 2 +OpDecorate %116 Flat +OpDecorate %118 Location 3 +OpDecorate %118 NoPerspective +OpDecorate %121 Location 4 +OpDecorate %121 NoPerspective +OpDecorate %121 Centroid +OpDecorate %124 Location 6 +OpDecorate %124 NoPerspective +OpDecorate %124 Sample +OpDecorate %127 Location 7 +OpDecorate %127 NoPerspective +OpDecorate %129 Location 8 +OpDecorate %131 Location 9 +OpDecorate %131 Centroid +OpDecorate %133 Location 10 +OpDecorate %133 Sample +OpDecorate %135 Location 11 %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 %5 = OpTypeInt 32 0 -%6 = OpTypeVector %4 2 -%7 = OpTypeVector %4 3 -%8 = OpTypeStruct %3 %5 %4 %6 %7 %3 %4 %4 -%11 = OpTypePointer Output %3 +%6 = OpTypeVector %3 2 +%7 = OpTypeVector %3 3 +%8 = OpTypeStruct %4 %5 %5 %5 %3 %6 %7 %7 %4 %3 %3 %3 +%11 = OpTypePointer Output %4 %10 = OpVariable %11 Output %13 = OpTypePointer Output %5 %12 = OpVariable %13 Output -%15 = OpTypePointer Output %4 -%14 = OpVariable %15 Output -%17 = OpTypePointer Output %6 +%14 = OpVariable %13 Output +%15 = OpVariable %13 Output +%17 = OpTypePointer Output %3 %16 = OpVariable %17 Output -%19 = OpTypePointer Output %7 +%19 = OpTypePointer Output %6 %18 = OpVariable %19 Output -%20 = OpVariable %11 Output -%21 = OpVariable %15 Output -%22 = OpVariable %15 Output -%24 = OpTypePointer Output %4 -%23 = OpVariable %24 Output -%25 = OpConstant %4 1.0 -%27 = OpTypeFunction %2 -%28 = OpConstant %4 2.0 -%29 = OpConstant %4 4.0 -%30 = OpConstant %4 5.0 -%31 = OpConstant %4 6.0 -%32 = OpConstantComposite %3 %28 %29 %30 %31 -%33 = OpConstant %5 8 -%34 = OpConstant %4 27.0 -%35 = OpConstant %4 64.0 -%36 = OpConstant %4 125.0 -%37 = OpConstantComposite %6 %35 %36 -%38 = OpConstant %4 216.0 -%39 = OpConstant %4 343.0 -%40 = OpConstant %4 512.0 -%41 = OpConstantComposite %7 %38 %39 %40 -%42 = OpConstant %4 729.0 -%43 = OpConstant %4 1000.0 -%44 = OpConstant %4 1331.0 -%45 = OpConstant %4 1728.0 -%46 = OpConstantComposite %3 %42 %43 %44 %45 -%47 = OpConstant %4 2197.0 -%48 = OpConstant %4 2744.0 -%50 = OpTypePointer Function %8 -%51 = OpConstantNull %8 -%53 = OpTypePointer Function %3 -%54 = OpConstant %5 0 -%56 = OpTypePointer Function %5 -%57 = OpConstant %5 1 -%59 = OpTypePointer Function %4 -%60 = OpConstant %5 2 -%62 = OpTypePointer Function %6 -%63 = OpConstant %5 3 -%65 = OpTypePointer Function %7 -%66 = OpConstant %5 4 -%68 = OpConstant %5 5 -%70 = OpConstant %5 6 -%72 = OpConstant %5 7 -%89 = OpTypePointer Input %3 -%88 = OpVariable %89 Input -%92 = OpTypePointer Input %5 -%91 = OpVariable %92 Input -%95 = OpTypePointer Input %4 -%94 = OpVariable %95 Input -%98 = OpTypePointer Input %6 -%97 = OpVariable %98 Input -%101 = OpTypePointer Input %7 -%100 = OpVariable %101 Input -%103 = OpVariable %89 Input -%105 = OpVariable %95 Input -%107 = OpVariable %95 Input -%26 = OpFunction %2 None %27 +%21 = OpTypePointer Output %7 +%20 = OpVariable %21 Output +%22 = OpVariable %21 Output +%23 = OpVariable %11 Output +%24 = OpVariable %17 Output +%25 = OpVariable %17 Output +%26 = OpVariable %17 Output +%28 = OpTypePointer Output %3 +%27 = OpVariable %28 Output +%29 = OpConstant %3 1.0 +%31 = OpTypeFunction %2 +%32 = OpConstant %3 2.0 +%33 = OpConstant %3 4.0 +%34 = OpConstant %3 5.0 +%35 = OpConstant %3 6.0 +%36 = OpConstantComposite %4 %32 %33 %34 %35 +%37 = OpConstant %5 8 +%38 = OpConstant %5 9 +%39 = OpConstant %5 10 +%40 = OpConstant %3 27.0 +%41 = OpConstant %3 64.0 +%42 = OpConstant %3 125.0 +%43 = OpConstantComposite %6 %41 %42 +%44 = OpConstant %3 216.0 +%45 = OpConstant %3 343.0 +%46 = OpConstant %3 512.0 +%47 = OpConstantComposite %7 %44 %45 %46 +%48 = OpConstant %3 255.0 +%49 = OpConstant %3 511.0 +%50 = OpConstant %3 1024.0 +%51 = OpConstantComposite %7 %48 %49 %50 +%52 = OpConstant %3 729.0 +%53 = OpConstant %3 1000.0 +%54 = OpConstant %3 1331.0 +%55 = OpConstant %3 1728.0 +%56 = OpConstantComposite %4 %52 %53 %54 %55 +%57 = OpConstant %3 2197.0 +%58 = OpConstant %3 2744.0 +%59 = OpConstant %3 2812.0 +%61 = OpTypePointer Function %8 +%62 = OpConstantNull %8 +%64 = OpTypePointer Function %4 +%65 = OpConstant %5 0 +%67 = OpTypePointer Function %5 +%68 = OpConstant %5 1 +%70 = OpConstant %5 2 +%72 = OpConstant %5 3 +%74 = OpTypePointer Function %3 +%75 = OpConstant %5 4 +%77 = OpTypePointer Function %6 +%78 = OpConstant %5 5 +%80 = OpTypePointer Function %7 +%81 = OpConstant %5 6 +%83 = OpConstant %5 7 +%88 = OpConstant %5 11 +%109 = OpTypePointer Input %4 +%108 = OpVariable %109 Input +%112 = OpTypePointer Input %5 +%111 = OpVariable %112 Input +%114 = OpVariable %112 Input +%116 = OpVariable %112 Input +%119 = OpTypePointer Input %3 +%118 = OpVariable %119 Input +%122 = OpTypePointer Input %6 +%121 = OpVariable %122 Input +%125 = OpTypePointer Input %7 +%124 = OpVariable %125 Input +%127 = OpVariable %125 Input +%129 = OpVariable %109 Input +%131 = OpVariable %119 Input +%133 = OpVariable %119 Input +%135 = OpVariable %119 Input +%30 = OpFunction %2 None %31 %9 = OpLabel -%49 = OpVariable %50 Function %51 -OpStore %23 %25 -OpBranch %52 -%52 = OpLabel -%55 = OpAccessChain %53 %49 %54 -OpStore %55 %32 -%58 = OpAccessChain %56 %49 %57 -OpStore %58 %33 -%61 = OpAccessChain %59 %49 %60 -OpStore %61 %34 -%64 = OpAccessChain %62 %49 %63 -OpStore %64 %37 -%67 = OpAccessChain %65 %49 %66 -OpStore %67 %41 -%69 = OpAccessChain %53 %49 %68 -OpStore %69 %46 -%71 = OpAccessChain %59 %49 %70 -OpStore %71 %47 -%73 = OpAccessChain %59 %49 %72 -OpStore %73 %48 -%74 = OpLoad %8 %49 -%75 = OpCompositeExtract %3 %74 0 -OpStore %10 %75 -%76 = OpAccessChain %24 %10 %57 -%77 = OpLoad %4 %76 -%78 = OpFNegate %4 %77 -OpStore %76 %78 -%79 = OpCompositeExtract %5 %74 1 -OpStore %12 %79 -%80 = OpCompositeExtract %4 %74 2 -OpStore %14 %80 -%81 = OpCompositeExtract %6 %74 3 -OpStore %16 %81 -%82 = OpCompositeExtract %7 %74 4 -OpStore %18 %82 -%83 = OpCompositeExtract %3 %74 5 -OpStore %20 %83 -%84 = OpCompositeExtract %4 %74 6 -OpStore %21 %84 -%85 = OpCompositeExtract %4 %74 7 -OpStore %22 %85 +%60 = OpVariable %61 Function %62 +OpStore %27 %29 +OpBranch %63 +%63 = OpLabel +%66 = OpAccessChain %64 %60 %65 +OpStore %66 %36 +%69 = OpAccessChain %67 %60 %68 +OpStore %69 %37 +%71 = OpAccessChain %67 %60 %70 +OpStore %71 %38 +%73 = OpAccessChain %67 %60 %72 +OpStore %73 %39 +%76 = OpAccessChain %74 %60 %75 +OpStore %76 %40 +%79 = OpAccessChain %77 %60 %78 +OpStore %79 %43 +%82 = OpAccessChain %80 %60 %81 +OpStore %82 %47 +%84 = OpAccessChain %80 %60 %83 +OpStore %84 %51 +%85 = OpAccessChain %64 %60 %37 +OpStore %85 %56 +%86 = OpAccessChain %74 %60 %38 +OpStore %86 %57 +%87 = OpAccessChain %74 %60 %39 +OpStore %87 %58 +%89 = OpAccessChain %74 %60 %88 +OpStore %89 %59 +%90 = OpLoad %8 %60 +%91 = OpCompositeExtract %4 %90 0 +OpStore %10 %91 +%92 = OpAccessChain %28 %10 %68 +%93 = OpLoad %3 %92 +%94 = OpFNegate %3 %93 +OpStore %92 %94 +%95 = OpCompositeExtract %5 %90 1 +OpStore %12 %95 +%96 = OpCompositeExtract %5 %90 2 +OpStore %14 %96 +%97 = OpCompositeExtract %5 %90 3 +OpStore %15 %97 +%98 = OpCompositeExtract %3 %90 4 +OpStore %16 %98 +%99 = OpCompositeExtract %6 %90 5 +OpStore %18 %99 +%100 = OpCompositeExtract %7 %90 6 +OpStore %20 %100 +%101 = OpCompositeExtract %7 %90 7 +OpStore %22 %101 +%102 = OpCompositeExtract %4 %90 8 +OpStore %23 %102 +%103 = OpCompositeExtract %3 %90 9 +OpStore %24 %103 +%104 = OpCompositeExtract %3 %90 10 +OpStore %25 %104 +%105 = OpCompositeExtract %3 %90 11 +OpStore %26 %105 OpReturn OpFunctionEnd -%109 = OpFunction %2 None %27 -%86 = OpLabel -%90 = OpLoad %3 %88 -%93 = OpLoad %5 %91 -%96 = OpLoad %4 %94 -%99 = OpLoad %6 %97 -%102 = OpLoad %7 %100 -%104 = OpLoad %3 %103 -%106 = OpLoad %4 %105 -%108 = OpLoad %4 %107 -%87 = OpCompositeConstruct %8 %90 %93 %96 %99 %102 %104 %106 %108 -OpBranch %110 -%110 = OpLabel +%137 = OpFunction %2 None %31 +%106 = OpLabel +%110 = OpLoad %4 %108 +%113 = OpLoad %5 %111 +%115 = OpLoad %5 %114 +%117 = OpLoad %5 %116 +%120 = OpLoad %3 %118 +%123 = OpLoad %6 %121 +%126 = OpLoad %7 %124 +%128 = OpLoad %7 %127 +%130 = OpLoad %4 %129 +%132 = OpLoad %3 %131 +%134 = OpLoad %3 %133 +%136 = OpLoad %3 %135 +%107 = OpCompositeConstruct %8 %110 %113 %115 %117 %120 %123 %126 %128 %130 %132 %134 %136 +OpBranch %138 +%138 = OpLabel OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/interpolate_compat.spvasm b/naga/tests/out/spv/interpolate_compat.spvasm new file mode 100644 index 0000000000..90f7237fd1 --- /dev/null +++ b/naga/tests/out/spv/interpolate_compat.spvasm @@ -0,0 +1,263 @@ +; SPIR-V +; Version: 1.0 +; Generator: rspirv +; Bound: 133 +OpCapability Shader +OpCapability SampleRateShading +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %29 "vert_main" %10 %12 %14 %15 %17 %19 %21 %22 %23 %24 %25 %26 +OpEntryPoint Fragment %131 "frag_main" %104 %107 %110 %112 %115 %118 %121 %123 %125 %127 %129 +OpExecutionMode %131 OriginUpperLeft +OpMemberName %8 0 "position" +OpMemberName %8 1 "_flat" +OpMemberName %8 2 "flat_either" +OpMemberName %8 3 "_linear" +OpMemberName %8 4 "linear_centroid" +OpMemberName %8 5 "linear_sample" +OpMemberName %8 6 "linear_center" +OpMemberName %8 7 "perspective" +OpMemberName %8 8 "perspective_centroid" +OpMemberName %8 9 "perspective_sample" +OpMemberName %8 10 "perspective_center" +OpName %8 "FragmentInput" +OpName %10 "position" +OpName %12 "_flat" +OpName %14 "flat_either" +OpName %15 "_linear" +OpName %17 "linear_centroid" +OpName %19 "linear_sample" +OpName %21 "linear_center" +OpName %22 "perspective" +OpName %23 "perspective_centroid" +OpName %24 "perspective_sample" +OpName %25 "perspective_center" +OpName %29 "vert_main" +OpName %58 "out" +OpName %104 "position" +OpName %107 "_flat" +OpName %110 "flat_either" +OpName %112 "_linear" +OpName %115 "linear_centroid" +OpName %118 "linear_sample" +OpName %121 "linear_center" +OpName %123 "perspective" +OpName %125 "perspective_centroid" +OpName %127 "perspective_sample" +OpName %129 "perspective_center" +OpName %131 "frag_main" +OpMemberDecorate %8 0 Offset 0 +OpMemberDecorate %8 1 Offset 16 +OpMemberDecorate %8 2 Offset 20 +OpMemberDecorate %8 3 Offset 24 +OpMemberDecorate %8 4 Offset 32 +OpMemberDecorate %8 5 Offset 48 +OpMemberDecorate %8 6 Offset 64 +OpMemberDecorate %8 7 Offset 80 +OpMemberDecorate %8 8 Offset 96 +OpMemberDecorate %8 9 Offset 100 +OpMemberDecorate %8 10 Offset 104 +OpDecorate %10 BuiltIn Position +OpDecorate %12 Location 0 +OpDecorate %12 Flat +OpDecorate %14 Location 2 +OpDecorate %14 Flat +OpDecorate %15 Location 3 +OpDecorate %15 NoPerspective +OpDecorate %17 Location 4 +OpDecorate %17 NoPerspective +OpDecorate %17 Centroid +OpDecorate %19 Location 6 +OpDecorate %19 NoPerspective +OpDecorate %19 Sample +OpDecorate %21 Location 7 +OpDecorate %21 NoPerspective +OpDecorate %22 Location 8 +OpDecorate %23 Location 9 +OpDecorate %23 Centroid +OpDecorate %24 Location 10 +OpDecorate %24 Sample +OpDecorate %25 Location 11 +OpDecorate %26 BuiltIn PointSize +OpDecorate %104 BuiltIn FragCoord +OpDecorate %107 Location 0 +OpDecorate %107 Flat +OpDecorate %110 Location 2 +OpDecorate %110 Flat +OpDecorate %112 Location 3 +OpDecorate %112 NoPerspective +OpDecorate %115 Location 4 +OpDecorate %115 NoPerspective +OpDecorate %115 Centroid +OpDecorate %118 Location 6 +OpDecorate %118 NoPerspective +OpDecorate %118 Sample +OpDecorate %121 Location 7 +OpDecorate %121 NoPerspective +OpDecorate %123 Location 8 +OpDecorate %125 Location 9 +OpDecorate %125 Centroid +OpDecorate %127 Location 10 +OpDecorate %127 Sample +OpDecorate %129 Location 11 +%2 = OpTypeVoid +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 +%5 = OpTypeInt 32 0 +%6 = OpTypeVector %3 2 +%7 = OpTypeVector %3 3 +%8 = OpTypeStruct %4 %5 %5 %3 %6 %7 %7 %4 %3 %3 %3 +%11 = OpTypePointer Output %4 +%10 = OpVariable %11 Output +%13 = OpTypePointer Output %5 +%12 = OpVariable %13 Output +%14 = OpVariable %13 Output +%16 = OpTypePointer Output %3 +%15 = OpVariable %16 Output +%18 = OpTypePointer Output %6 +%17 = OpVariable %18 Output +%20 = OpTypePointer Output %7 +%19 = OpVariable %20 Output +%21 = OpVariable %20 Output +%22 = OpVariable %11 Output +%23 = OpVariable %16 Output +%24 = OpVariable %16 Output +%25 = OpVariable %16 Output +%27 = OpTypePointer Output %3 +%26 = OpVariable %27 Output +%28 = OpConstant %3 1.0 +%30 = OpTypeFunction %2 +%31 = OpConstant %3 2.0 +%32 = OpConstant %3 4.0 +%33 = OpConstant %3 5.0 +%34 = OpConstant %3 6.0 +%35 = OpConstantComposite %4 %31 %32 %33 %34 +%36 = OpConstant %5 8 +%37 = OpConstant %5 10 +%38 = OpConstant %3 27.0 +%39 = OpConstant %3 64.0 +%40 = OpConstant %3 125.0 +%41 = OpConstantComposite %6 %39 %40 +%42 = OpConstant %3 216.0 +%43 = OpConstant %3 343.0 +%44 = OpConstant %3 512.0 +%45 = OpConstantComposite %7 %42 %43 %44 +%46 = OpConstant %3 255.0 +%47 = OpConstant %3 511.0 +%48 = OpConstant %3 1024.0 +%49 = OpConstantComposite %7 %46 %47 %48 +%50 = OpConstant %3 729.0 +%51 = OpConstant %3 1000.0 +%52 = OpConstant %3 1331.0 +%53 = OpConstant %3 1728.0 +%54 = OpConstantComposite %4 %50 %51 %52 %53 +%55 = OpConstant %3 2197.0 +%56 = OpConstant %3 2744.0 +%57 = OpConstant %3 2812.0 +%59 = OpTypePointer Function %8 +%60 = OpConstantNull %8 +%62 = OpTypePointer Function %4 +%63 = OpConstant %5 0 +%65 = OpTypePointer Function %5 +%66 = OpConstant %5 1 +%68 = OpConstant %5 2 +%70 = OpTypePointer Function %3 +%71 = OpConstant %5 3 +%73 = OpTypePointer Function %6 +%74 = OpConstant %5 4 +%76 = OpTypePointer Function %7 +%77 = OpConstant %5 5 +%79 = OpConstant %5 6 +%81 = OpConstant %5 7 +%84 = OpConstant %5 9 +%105 = OpTypePointer Input %4 +%104 = OpVariable %105 Input +%108 = OpTypePointer Input %5 +%107 = OpVariable %108 Input +%110 = OpVariable %108 Input +%113 = OpTypePointer Input %3 +%112 = OpVariable %113 Input +%116 = OpTypePointer Input %6 +%115 = OpVariable %116 Input +%119 = OpTypePointer Input %7 +%118 = OpVariable %119 Input +%121 = OpVariable %119 Input +%123 = OpVariable %105 Input +%125 = OpVariable %113 Input +%127 = OpVariable %113 Input +%129 = OpVariable %113 Input +%29 = OpFunction %2 None %30 +%9 = OpLabel +%58 = OpVariable %59 Function %60 +OpStore %26 %28 +OpBranch %61 +%61 = OpLabel +%64 = OpAccessChain %62 %58 %63 +OpStore %64 %35 +%67 = OpAccessChain %65 %58 %66 +OpStore %67 %36 +%69 = OpAccessChain %65 %58 %68 +OpStore %69 %37 +%72 = OpAccessChain %70 %58 %71 +OpStore %72 %38 +%75 = OpAccessChain %73 %58 %74 +OpStore %75 %41 +%78 = OpAccessChain %76 %58 %77 +OpStore %78 %45 +%80 = OpAccessChain %76 %58 %79 +OpStore %80 %49 +%82 = OpAccessChain %62 %58 %81 +OpStore %82 %54 +%83 = OpAccessChain %70 %58 %36 +OpStore %83 %55 +%85 = OpAccessChain %70 %58 %84 +OpStore %85 %56 +%86 = OpAccessChain %70 %58 %37 +OpStore %86 %57 +%87 = OpLoad %8 %58 +%88 = OpCompositeExtract %4 %87 0 +OpStore %10 %88 +%89 = OpAccessChain %27 %10 %66 +%90 = OpLoad %3 %89 +%91 = OpFNegate %3 %90 +OpStore %89 %91 +%92 = OpCompositeExtract %5 %87 1 +OpStore %12 %92 +%93 = OpCompositeExtract %5 %87 2 +OpStore %14 %93 +%94 = OpCompositeExtract %3 %87 3 +OpStore %15 %94 +%95 = OpCompositeExtract %6 %87 4 +OpStore %17 %95 +%96 = OpCompositeExtract %7 %87 5 +OpStore %19 %96 +%97 = OpCompositeExtract %7 %87 6 +OpStore %21 %97 +%98 = OpCompositeExtract %4 %87 7 +OpStore %22 %98 +%99 = OpCompositeExtract %3 %87 8 +OpStore %23 %99 +%100 = OpCompositeExtract %3 %87 9 +OpStore %24 %100 +%101 = OpCompositeExtract %3 %87 10 +OpStore %25 %101 +OpReturn +OpFunctionEnd +%131 = OpFunction %2 None %30 +%102 = OpLabel +%106 = OpLoad %4 %104 +%109 = OpLoad %5 %107 +%111 = OpLoad %5 %110 +%114 = OpLoad %3 %112 +%117 = OpLoad %6 %115 +%120 = OpLoad %7 %118 +%122 = OpLoad %7 %121 +%124 = OpLoad %4 %123 +%126 = OpLoad %3 %125 +%128 = OpLoad %3 %127 +%130 = OpLoad %3 %129 +%103 = OpCompositeConstruct %8 %106 %109 %111 %114 %117 %120 %122 %124 %126 %128 %130 +OpBranch %132 +%132 = OpLabel +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/math-functions.spvasm b/naga/tests/out/spv/math-functions.spvasm index 366857f91f..47efe2a6fe 100644 --- a/naga/tests/out/spv/math-functions.spvasm +++ b/naga/tests/out/spv/math-functions.spvasm @@ -18,27 +18,27 @@ OpMemberDecorate %14 1 Offset 4 OpMemberDecorate %15 0 Offset 0 OpMemberDecorate %15 1 Offset 16 %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 %6 = OpTypeInt 32 1 %5 = OpTypeVector %6 4 %7 = OpTypeVector %6 2 %9 = OpTypeInt 32 0 %8 = OpTypeVector %9 2 -%10 = OpTypeVector %4 2 -%11 = OpTypeStruct %4 %4 +%10 = OpTypeVector %3 2 +%11 = OpTypeStruct %3 %3 %12 = OpTypeStruct %10 %10 -%13 = OpTypeStruct %3 %3 -%14 = OpTypeStruct %4 %6 -%15 = OpTypeStruct %3 %5 +%13 = OpTypeStruct %4 %4 +%14 = OpTypeStruct %3 %6 +%15 = OpTypeStruct %4 %5 %18 = OpTypeFunction %2 -%19 = OpConstant %4 1.0 -%20 = OpConstant %4 0.0 -%21 = OpConstantComposite %3 %20 %20 %20 %20 +%19 = OpConstant %3 1.0 +%20 = OpConstant %3 0.0 +%21 = OpConstantComposite %4 %20 %20 %20 %20 %22 = OpConstant %6 -1 %23 = OpConstantComposite %5 %22 %22 %22 %22 -%24 = OpConstant %4 -1.0 -%25 = OpConstantComposite %3 %24 %24 %24 %24 +%24 = OpConstant %3 -1.0 +%25 = OpConstantComposite %4 %24 %24 %24 %24 %26 = OpConstantNull %7 %27 = OpConstant %9 4294967295 %28 = OpConstantComposite %7 %22 %22 @@ -53,26 +53,26 @@ OpMemberDecorate %15 1 Offset 16 %37 = OpConstant %9 31 %38 = OpConstantComposite %8 %37 %37 %39 = OpConstant %6 2 -%40 = OpConstant %4 2.0 +%40 = OpConstant %3 2.0 %41 = OpConstantComposite %10 %19 %40 %42 = OpConstant %6 3 %43 = OpConstant %6 4 %44 = OpConstantComposite %7 %42 %43 -%45 = OpConstant %4 1.5 +%45 = OpConstant %3 1.5 %46 = OpConstantComposite %10 %45 %45 -%47 = OpConstantComposite %3 %45 %45 %45 %45 -%54 = OpConstantComposite %3 %19 %19 %19 %19 +%47 = OpConstantComposite %4 %45 %45 %45 %45 +%54 = OpConstantComposite %4 %19 %19 %19 %19 %57 = OpConstantNull %6 %17 = OpFunction %2 None %18 %16 = OpLabel OpBranch %48 %48 = OpLabel -%49 = OpExtInst %4 %1 Degrees %19 -%50 = OpExtInst %4 %1 Radians %19 -%51 = OpExtInst %3 %1 Degrees %21 -%52 = OpExtInst %3 %1 Radians %21 -%53 = OpExtInst %3 %1 FClamp %21 %21 %54 -%55 = OpExtInst %3 %1 Refract %21 %21 %19 +%49 = OpExtInst %3 %1 Degrees %19 +%50 = OpExtInst %3 %1 Radians %19 +%51 = OpExtInst %4 %1 Degrees %21 +%52 = OpExtInst %4 %1 Radians %21 +%53 = OpExtInst %4 %1 FClamp %21 %21 %54 +%55 = OpExtInst %4 %1 Refract %21 %21 %19 %58 = OpCompositeExtract %6 %26 0 %59 = OpCompositeExtract %6 %26 0 %60 = OpIMul %6 %58 %59 @@ -81,23 +81,23 @@ OpBranch %48 %63 = OpCompositeExtract %6 %26 1 %64 = OpIMul %6 %62 %63 %56 = OpIAdd %6 %61 %64 -%65 = OpExtInst %4 %1 Ldexp %19 %39 +%65 = OpExtInst %3 %1 Ldexp %19 %39 %66 = OpExtInst %10 %1 Ldexp %41 %44 %67 = OpExtInst %11 %1 ModfStruct %45 %68 = OpExtInst %11 %1 ModfStruct %45 -%69 = OpCompositeExtract %4 %68 0 +%69 = OpCompositeExtract %3 %68 0 %70 = OpExtInst %11 %1 ModfStruct %45 -%71 = OpCompositeExtract %4 %70 1 +%71 = OpCompositeExtract %3 %70 1 %72 = OpExtInst %12 %1 ModfStruct %46 %73 = OpExtInst %13 %1 ModfStruct %47 -%74 = OpCompositeExtract %3 %73 1 -%75 = OpCompositeExtract %4 %74 0 +%74 = OpCompositeExtract %4 %73 1 +%75 = OpCompositeExtract %3 %74 0 %76 = OpExtInst %12 %1 ModfStruct %46 %77 = OpCompositeExtract %10 %76 0 -%78 = OpCompositeExtract %4 %77 1 +%78 = OpCompositeExtract %3 %77 1 %79 = OpExtInst %14 %1 FrexpStruct %45 %80 = OpExtInst %14 %1 FrexpStruct %45 -%81 = OpCompositeExtract %4 %80 0 +%81 = OpCompositeExtract %3 %80 0 %82 = OpExtInst %14 %1 FrexpStruct %45 %83 = OpCompositeExtract %6 %82 1 %84 = OpExtInst %15 %1 FrexpStruct %47 diff --git a/naga/tests/out/spv/operators.spvasm b/naga/tests/out/spv/operators.spvasm index 974623bc70..a59c2e5558 100644 --- a/naga/tests/out/spv/operators.spvasm +++ b/naga/tests/out/spv/operators.spvasm @@ -9,47 +9,47 @@ OpEntryPoint GLCompute %374 "main" %371 OpExecutionMode %374 LocalSize 1 1 1 OpDecorate %371 BuiltIn WorkgroupId %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 -%6 = OpTypeInt 32 1 -%5 = OpTypeVector %6 4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 +%5 = OpTypeInt 32 1 +%6 = OpTypeVector %5 4 %8 = OpTypeBool %7 = OpTypeVector %8 4 -%9 = OpTypeVector %4 2 -%10 = OpTypeVector %4 3 +%9 = OpTypeVector %3 2 +%10 = OpTypeVector %3 3 %11 = OpTypeMatrix %10 3 %12 = OpTypeMatrix %10 4 -%13 = OpTypeMatrix %3 3 -%14 = OpTypeVector %6 3 +%13 = OpTypeMatrix %4 3 +%14 = OpTypeVector %5 3 %16 = OpTypeInt 32 0 %15 = OpTypeVector %16 3 -%17 = OpConstant %4 1.0 -%18 = OpConstantComposite %3 %17 %17 %17 %17 -%19 = OpConstant %4 0.0 -%20 = OpConstantComposite %3 %19 %19 %19 %19 -%21 = OpConstant %4 0.5 -%22 = OpConstantComposite %3 %21 %21 %21 %21 -%23 = OpConstant %6 1 -%24 = OpConstantComposite %5 %23 %23 %23 %23 -%27 = OpTypeFunction %3 +%17 = OpConstant %3 1.0 +%18 = OpConstantComposite %4 %17 %17 %17 %17 +%19 = OpConstant %3 0.0 +%20 = OpConstantComposite %4 %19 %19 %19 %19 +%21 = OpConstant %3 0.5 +%22 = OpConstantComposite %4 %21 %21 %21 %21 +%23 = OpConstant %5 1 +%24 = OpConstantComposite %6 %23 %23 %23 %23 +%27 = OpTypeFunction %4 %28 = OpConstantTrue %8 -%29 = OpConstant %6 0 +%29 = OpConstant %5 0 %30 = OpConstantFalse %8 %31 = OpConstantComposite %7 %30 %30 %30 %30 -%32 = OpConstant %4 0.1 -%33 = OpConstantComposite %5 %29 %29 %29 %29 -%57 = OpTypeFunction %3 %4 %6 -%58 = OpConstant %4 2.0 +%32 = OpConstant %3 0.1 +%33 = OpConstantComposite %6 %29 %29 %29 %29 +%57 = OpTypeFunction %4 %3 %5 +%58 = OpConstant %3 2.0 %59 = OpConstantComposite %9 %58 %58 -%60 = OpConstant %4 4.0 +%60 = OpConstant %3 4.0 %61 = OpConstantComposite %9 %60 %60 -%62 = OpConstant %4 8.0 +%62 = OpConstant %3 8.0 %63 = OpConstantComposite %9 %62 %62 -%64 = OpConstant %6 2 -%65 = OpConstantComposite %5 %64 %64 %64 %64 +%64 = OpConstant %5 2 +%65 = OpConstantComposite %6 %64 %64 %64 %64 %78 = OpTypeFunction %9 %79 = OpConstantComposite %9 %17 %17 -%80 = OpConstant %4 3.0 +%80 = OpConstant %3 3.0 %81 = OpConstantComposite %9 %80 %80 %83 = OpTypePointer Function %9 %95 = OpTypeFunction %10 %10 @@ -65,13 +65,13 @@ OpDecorate %371 BuiltIn WorkgroupId %110 = OpConstantComposite %7 %30 %30 %30 %30 %122 = OpConstant %16 1 %123 = OpConstant %16 2 -%124 = OpTypeVector %6 2 +%124 = OpTypeVector %5 2 %125 = OpConstantComposite %124 %23 %23 %126 = OpConstantComposite %124 %64 %64 %127 = OpConstantComposite %15 %123 %123 %123 %128 = OpConstantComposite %15 %122 %122 %122 -%129 = OpConstantComposite %3 %58 %58 %58 %58 -%130 = OpConstantComposite %3 %17 %17 %17 %17 +%129 = OpConstantComposite %4 %58 %58 %58 %58 +%130 = OpConstantComposite %4 %17 %17 %17 %17 %131 = OpTypeVector %16 2 %132 = OpConstantComposite %131 %123 %123 %133 = OpConstantComposite %131 %122 %122 @@ -80,40 +80,40 @@ OpDecorate %371 BuiltIn WorkgroupId %136 = OpConstantComposite %10 %58 %58 %58 %137 = OpConstantNull %13 %301 = OpConstantNull %14 -%303 = OpTypePointer Function %6 -%304 = OpConstantNull %6 +%303 = OpTypePointer Function %5 +%304 = OpConstantNull %5 %306 = OpTypePointer Function %14 -%334 = OpTypePointer Function %6 +%334 = OpTypePointer Function %5 %372 = OpTypePointer Input %15 %371 = OpVariable %372 Input %375 = OpConstantComposite %10 %17 %17 %17 -%26 = OpFunction %3 None %27 +%26 = OpFunction %4 None %27 %25 = OpLabel OpBranch %34 %34 = OpLabel -%35 = OpSelect %6 %28 %23 %29 +%35 = OpSelect %5 %28 %23 %29 %37 = OpCompositeConstruct %7 %28 %28 %28 %28 -%36 = OpSelect %3 %37 %18 %20 -%38 = OpSelect %3 %31 %20 %18 -%39 = OpExtInst %3 %1 FMix %20 %18 %22 -%41 = OpCompositeConstruct %3 %32 %32 %32 %32 -%40 = OpExtInst %3 %1 FMix %20 %18 %41 -%42 = OpBitcast %4 %23 -%43 = OpBitcast %3 %24 -%44 = OpCompositeConstruct %5 %35 %35 %35 %35 -%45 = OpIAdd %5 %44 %33 -%46 = OpConvertSToF %3 %45 -%47 = OpFAdd %3 %46 %36 -%48 = OpFAdd %3 %47 %39 -%49 = OpFAdd %3 %48 %40 -%50 = OpCompositeConstruct %3 %42 %42 %42 %42 -%51 = OpFAdd %3 %49 %50 -%52 = OpFAdd %3 %51 %43 +%36 = OpSelect %4 %37 %18 %20 +%38 = OpSelect %4 %31 %20 %18 +%39 = OpExtInst %4 %1 FMix %20 %18 %22 +%41 = OpCompositeConstruct %4 %32 %32 %32 %32 +%40 = OpExtInst %4 %1 FMix %20 %18 %41 +%42 = OpBitcast %3 %23 +%43 = OpBitcast %4 %24 +%44 = OpCompositeConstruct %6 %35 %35 %35 %35 +%45 = OpIAdd %6 %44 %33 +%46 = OpConvertSToF %4 %45 +%47 = OpFAdd %4 %46 %36 +%48 = OpFAdd %4 %47 %39 +%49 = OpFAdd %4 %48 %40 +%50 = OpCompositeConstruct %4 %42 %42 %42 %42 +%51 = OpFAdd %4 %49 %50 +%52 = OpFAdd %4 %51 %43 OpReturnValue %52 OpFunctionEnd -%56 = OpFunction %3 None %57 -%54 = OpFunctionParameter %4 -%55 = OpFunctionParameter %6 +%56 = OpFunction %4 None %57 +%54 = OpFunctionParameter %3 +%55 = OpFunctionParameter %5 %53 = OpLabel OpBranch %66 %66 = OpLabel @@ -121,11 +121,11 @@ OpBranch %66 %68 = OpFAdd %9 %59 %67 %69 = OpFSub %9 %68 %61 %70 = OpFDiv %9 %69 %63 -%71 = OpCompositeConstruct %5 %55 %55 %55 %55 -%72 = OpSRem %5 %71 %65 -%73 = OpVectorShuffle %3 %70 %70 0 1 0 1 -%74 = OpConvertSToF %3 %72 -%75 = OpFAdd %3 %73 %74 +%71 = OpCompositeConstruct %6 %55 %55 %55 %55 +%72 = OpSRem %6 %71 %65 +%73 = OpVectorShuffle %4 %70 %70 0 1 0 1 +%74 = OpConvertSToF %4 %72 +%75 = OpFAdd %4 %73 %74 OpReturnValue %75 OpFunctionEnd %77 = OpFunction %9 None %78 @@ -172,39 +172,39 @@ OpFunctionEnd %120 = OpLabel OpBranch %138 %138 = OpLabel -%139 = OpFNegate %4 %17 +%139 = OpFNegate %3 %17 %140 = OpSNegate %124 %125 %141 = OpFNegate %9 %79 -%142 = OpIAdd %6 %64 %23 +%142 = OpIAdd %5 %64 %23 %143 = OpIAdd %16 %123 %122 -%144 = OpFAdd %4 %58 %17 +%144 = OpFAdd %3 %58 %17 %145 = OpIAdd %124 %126 %125 %146 = OpIAdd %15 %127 %128 -%147 = OpFAdd %3 %129 %130 -%148 = OpISub %6 %64 %23 +%147 = OpFAdd %4 %129 %130 +%148 = OpISub %5 %64 %23 %149 = OpISub %16 %123 %122 -%150 = OpFSub %4 %58 %17 +%150 = OpFSub %3 %58 %17 %151 = OpISub %124 %126 %125 %152 = OpISub %15 %127 %128 -%153 = OpFSub %3 %129 %130 -%154 = OpIMul %6 %64 %23 +%153 = OpFSub %4 %129 %130 +%154 = OpIMul %5 %64 %23 %155 = OpIMul %16 %123 %122 -%156 = OpFMul %4 %58 %17 +%156 = OpFMul %3 %58 %17 %157 = OpIMul %124 %126 %125 %158 = OpIMul %15 %127 %128 -%159 = OpFMul %3 %129 %130 -%160 = OpSDiv %6 %64 %23 +%159 = OpFMul %4 %129 %130 +%160 = OpSDiv %5 %64 %23 %161 = OpUDiv %16 %123 %122 -%162 = OpFDiv %4 %58 %17 +%162 = OpFDiv %3 %58 %17 %163 = OpSDiv %124 %126 %125 %164 = OpUDiv %15 %127 %128 -%165 = OpFDiv %3 %129 %130 -%166 = OpSRem %6 %64 %23 +%165 = OpFDiv %4 %129 %130 +%166 = OpSRem %5 %64 %23 %167 = OpUMod %16 %123 %122 -%168 = OpFRem %4 %58 %17 +%168 = OpFRem %3 %58 %17 %169 = OpSRem %124 %126 %125 %170 = OpUMod %15 %127 %128 -%171 = OpFRem %3 %129 %130 +%171 = OpFRem %4 %129 %130 OpBranch %172 %172 = OpLabel %174 = OpIAdd %124 %126 %125 @@ -266,7 +266,7 @@ OpBranch %173 %228 = OpMatrixTimesScalar %11 %134 %17 %229 = OpMatrixTimesScalar %11 %134 %58 %230 = OpMatrixTimesVector %10 %135 %130 -%231 = OpVectorTimesMatrix %3 %136 %135 +%231 = OpVectorTimesMatrix %4 %136 %135 %232 = OpMatrixTimesMatrix %11 %135 %137 OpReturn OpFunctionEnd @@ -274,27 +274,27 @@ OpFunctionEnd %233 = OpLabel OpBranch %235 %235 = OpLabel -%236 = OpNot %6 %23 +%236 = OpNot %5 %23 %237 = OpNot %16 %122 %238 = OpNot %124 %125 %239 = OpNot %15 %128 -%240 = OpBitwiseOr %6 %64 %23 +%240 = OpBitwiseOr %5 %64 %23 %241 = OpBitwiseOr %16 %123 %122 %242 = OpBitwiseOr %124 %126 %125 %243 = OpBitwiseOr %15 %127 %128 -%244 = OpBitwiseAnd %6 %64 %23 +%244 = OpBitwiseAnd %5 %64 %23 %245 = OpBitwiseAnd %16 %123 %122 %246 = OpBitwiseAnd %124 %126 %125 %247 = OpBitwiseAnd %15 %127 %128 -%248 = OpBitwiseXor %6 %64 %23 +%248 = OpBitwiseXor %5 %64 %23 %249 = OpBitwiseXor %16 %123 %122 %250 = OpBitwiseXor %124 %126 %125 %251 = OpBitwiseXor %15 %127 %128 -%252 = OpShiftLeftLogical %6 %64 %122 +%252 = OpShiftLeftLogical %5 %64 %122 %253 = OpShiftLeftLogical %16 %123 %122 %254 = OpShiftLeftLogical %124 %126 %133 %255 = OpShiftLeftLogical %15 %127 %128 -%256 = OpShiftRightArithmetic %6 %64 %122 +%256 = OpShiftRightArithmetic %5 %64 %122 %257 = OpShiftRightLogical %16 %123 %122 %258 = OpShiftRightArithmetic %124 %126 %133 %259 = OpShiftRightLogical %15 %127 %128 @@ -349,52 +349,52 @@ OpFunctionEnd OpBranch %307 %307 = OpLabel OpStore %302 %23 -%308 = OpLoad %6 %302 -%309 = OpIAdd %6 %308 %23 +%308 = OpLoad %5 %302 +%309 = OpIAdd %5 %308 %23 OpStore %302 %309 -%310 = OpLoad %6 %302 -%311 = OpISub %6 %310 %23 +%310 = OpLoad %5 %302 +%311 = OpISub %5 %310 %23 OpStore %302 %311 -%312 = OpLoad %6 %302 -%313 = OpLoad %6 %302 -%314 = OpIMul %6 %313 %312 +%312 = OpLoad %5 %302 +%313 = OpLoad %5 %302 +%314 = OpIMul %5 %313 %312 OpStore %302 %314 -%315 = OpLoad %6 %302 -%316 = OpLoad %6 %302 -%317 = OpSDiv %6 %316 %315 +%315 = OpLoad %5 %302 +%316 = OpLoad %5 %302 +%317 = OpSDiv %5 %316 %315 OpStore %302 %317 -%318 = OpLoad %6 %302 -%319 = OpSRem %6 %318 %23 +%318 = OpLoad %5 %302 +%319 = OpSRem %5 %318 %23 OpStore %302 %319 -%320 = OpLoad %6 %302 -%321 = OpBitwiseAnd %6 %320 %29 +%320 = OpLoad %5 %302 +%321 = OpBitwiseAnd %5 %320 %29 OpStore %302 %321 -%322 = OpLoad %6 %302 -%323 = OpBitwiseOr %6 %322 %29 +%322 = OpLoad %5 %302 +%323 = OpBitwiseOr %5 %322 %29 OpStore %302 %323 -%324 = OpLoad %6 %302 -%325 = OpBitwiseXor %6 %324 %29 +%324 = OpLoad %5 %302 +%325 = OpBitwiseXor %5 %324 %29 OpStore %302 %325 -%326 = OpLoad %6 %302 -%327 = OpShiftLeftLogical %6 %326 %123 +%326 = OpLoad %5 %302 +%327 = OpShiftLeftLogical %5 %326 %123 OpStore %302 %327 -%328 = OpLoad %6 %302 -%329 = OpShiftRightArithmetic %6 %328 %122 +%328 = OpLoad %5 %302 +%329 = OpShiftRightArithmetic %5 %328 %122 OpStore %302 %329 -%330 = OpLoad %6 %302 -%331 = OpIAdd %6 %330 %23 +%330 = OpLoad %5 %302 +%331 = OpIAdd %5 %330 %23 OpStore %302 %331 -%332 = OpLoad %6 %302 -%333 = OpISub %6 %332 %23 +%332 = OpLoad %5 %302 +%333 = OpISub %5 %332 %23 OpStore %302 %333 %335 = OpAccessChain %334 %305 %23 -%336 = OpLoad %6 %335 -%337 = OpIAdd %6 %336 %23 +%336 = OpLoad %5 %335 +%337 = OpIAdd %5 %336 %23 %338 = OpAccessChain %334 %305 %23 OpStore %338 %337 %339 = OpAccessChain %334 %305 %23 -%340 = OpLoad %6 %339 -%341 = OpISub %6 %340 %23 +%340 = OpLoad %5 %339 +%341 = OpISub %5 %340 %23 %342 = OpAccessChain %334 %305 %23 OpStore %342 %341 OpReturn @@ -403,30 +403,30 @@ OpFunctionEnd %343 = OpLabel OpBranch %345 %345 = OpLabel -%346 = OpSNegate %6 %23 -%347 = OpSNegate %6 %23 -%348 = OpSNegate %6 %347 -%349 = OpSNegate %6 %23 -%350 = OpSNegate %6 %349 -%351 = OpSNegate %6 %23 -%352 = OpSNegate %6 %351 -%353 = OpSNegate %6 %23 -%354 = OpSNegate %6 %353 -%355 = OpSNegate %6 %354 -%356 = OpSNegate %6 %23 -%357 = OpSNegate %6 %356 -%358 = OpSNegate %6 %357 -%359 = OpSNegate %6 %358 -%360 = OpSNegate %6 %23 -%361 = OpSNegate %6 %360 -%362 = OpSNegate %6 %361 -%363 = OpSNegate %6 %362 -%364 = OpSNegate %6 %363 -%365 = OpSNegate %6 %23 -%366 = OpSNegate %6 %365 -%367 = OpSNegate %6 %366 -%368 = OpSNegate %6 %367 -%369 = OpSNegate %6 %368 +%346 = OpSNegate %5 %23 +%347 = OpSNegate %5 %23 +%348 = OpSNegate %5 %347 +%349 = OpSNegate %5 %23 +%350 = OpSNegate %5 %349 +%351 = OpSNegate %5 %23 +%352 = OpSNegate %5 %351 +%353 = OpSNegate %5 %23 +%354 = OpSNegate %5 %353 +%355 = OpSNegate %5 %354 +%356 = OpSNegate %5 %23 +%357 = OpSNegate %5 %356 +%358 = OpSNegate %5 %357 +%359 = OpSNegate %5 %358 +%360 = OpSNegate %5 %23 +%361 = OpSNegate %5 %360 +%362 = OpSNegate %5 %361 +%363 = OpSNegate %5 %362 +%364 = OpSNegate %5 %363 +%365 = OpSNegate %5 %23 +%366 = OpSNegate %5 %365 +%367 = OpSNegate %5 %366 +%368 = OpSNegate %5 %367 +%369 = OpSNegate %5 %368 OpReturn OpFunctionEnd %374 = OpFunction %2 None %104 @@ -434,12 +434,12 @@ OpFunctionEnd %373 = OpLoad %15 %371 OpBranch %376 %376 = OpLabel -%377 = OpFunctionCall %3 %26 +%377 = OpFunctionCall %4 %26 %378 = OpCompositeExtract %16 %373 0 -%379 = OpConvertUToF %4 %378 +%379 = OpConvertUToF %3 %378 %380 = OpCompositeExtract %16 %373 1 -%381 = OpBitcast %6 %380 -%382 = OpFunctionCall %3 %56 %379 %381 +%381 = OpBitcast %5 %380 +%382 = OpFunctionCall %4 %56 %379 %381 %383 = OpFunctionCall %10 %94 %375 %384 = OpFunctionCall %2 %103 %385 = OpFunctionCall %2 %121 diff --git a/naga/tests/out/spv/padding.spvasm b/naga/tests/out/spv/padding.spvasm index aae9f2cb74..b7b21f17ed 100644 --- a/naga/tests/out/spv/padding.spvasm +++ b/naga/tests/out/spv/padding.spvasm @@ -45,17 +45,17 @@ OpDecorate %21 Block OpMemberDecorate %21 0 Offset 0 OpDecorate %24 BuiltIn Position %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 3 -%5 = OpTypeStruct %3 -%6 = OpTypeStruct %5 %4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 3 +%5 = OpTypeStruct %4 +%6 = OpTypeStruct %5 %3 %9 = OpTypeInt 32 0 %8 = OpConstant %9 2 -%7 = OpTypeArray %3 %8 -%10 = OpTypeStruct %7 %4 -%11 = OpTypeMatrix %3 4 -%12 = OpTypeStruct %11 %4 -%13 = OpTypeVector %4 4 +%7 = OpTypeArray %4 %8 +%10 = OpTypeStruct %7 %3 +%11 = OpTypeMatrix %4 4 +%12 = OpTypeStruct %11 %3 +%13 = OpTypeVector %3 4 %15 = OpTypeStruct %6 %16 = OpTypePointer Uniform %15 %14 = OpVariable %16 Uniform @@ -72,9 +72,9 @@ OpDecorate %24 BuiltIn Position %29 = OpConstant %9 0 %31 = OpTypePointer Uniform %10 %33 = OpTypePointer Uniform %12 -%35 = OpConstant %4 1.0 +%35 = OpConstant %3 1.0 %36 = OpConstantComposite %13 %35 %35 %35 %35 -%38 = OpTypePointer Uniform %4 +%38 = OpTypePointer Uniform %3 %39 = OpConstant %9 1 %26 = OpFunction %2 None %27 %23 = OpLabel @@ -84,13 +84,13 @@ OpDecorate %24 BuiltIn Position OpBranch %37 %37 = OpLabel %40 = OpAccessChain %38 %30 %39 -%41 = OpLoad %4 %40 +%41 = OpLoad %3 %40 %42 = OpVectorTimesScalar %13 %36 %41 %43 = OpAccessChain %38 %32 %39 -%44 = OpLoad %4 %43 +%44 = OpLoad %3 %43 %45 = OpVectorTimesScalar %13 %42 %44 %46 = OpAccessChain %38 %34 %39 -%47 = OpLoad %4 %46 +%47 = OpLoad %3 %46 %48 = OpVectorTimesScalar %13 %45 %47 OpStore %24 %48 OpReturn diff --git a/naga/tests/out/spv/pointers.spvasm b/naga/tests/out/spv/pointers.spvasm index ae42aed2e0..07658a21a1 100644 --- a/naga/tests/out/spv/pointers.spvasm +++ b/naga/tests/out/spv/pointers.spvasm @@ -24,20 +24,20 @@ OpDecorate %7 Block OpDecorate %8 DescriptorSet 0 OpDecorate %8 Binding 0 %2 = OpTypeVoid -%4 = OpTypeInt 32 1 -%3 = OpTypeVector %4 2 +%3 = OpTypeInt 32 1 +%4 = OpTypeVector %3 2 %5 = OpTypeInt 32 0 %6 = OpTypeRuntimeArray %5 %7 = OpTypeStruct %6 %9 = OpTypePointer StorageBuffer %7 %8 = OpVariable %9 StorageBuffer %12 = OpTypeFunction %2 -%13 = OpConstant %4 10 -%15 = OpTypePointer Function %3 -%16 = OpConstantNull %3 -%18 = OpTypePointer Function %4 +%13 = OpConstant %3 10 +%15 = OpTypePointer Function %4 +%16 = OpConstantNull %4 +%18 = OpTypePointer Function %3 %19 = OpConstant %5 0 -%25 = OpTypeFunction %2 %4 %5 +%25 = OpTypeFunction %2 %3 %5 %27 = OpTypePointer StorageBuffer %6 %28 = OpTypePointer StorageBuffer %5 %11 = OpFunction %2 None %12 @@ -50,7 +50,7 @@ OpStore %20 %13 OpReturn OpFunctionEnd %24 = OpFunction %2 None %25 -%22 = OpFunctionParameter %4 +%22 = OpFunctionParameter %3 %23 = OpFunctionParameter %5 %21 = OpLabel OpBranch %26 @@ -63,7 +63,7 @@ OpStore %32 %31 OpReturn OpFunctionEnd %36 = OpFunction %2 None %25 -%34 = OpFunctionParameter %4 +%34 = OpFunctionParameter %3 %35 = OpFunctionParameter %5 %33 = OpLabel OpBranch %37 diff --git a/naga/tests/out/spv/policy-mix.spvasm b/naga/tests/out/spv/policy-mix.spvasm index a10ff1121f..f517777987 100644 --- a/naga/tests/out/spv/policy-mix.spvasm +++ b/naga/tests/out/spv/policy-mix.spvasm @@ -41,24 +41,24 @@ OpMemberDecorate %25 0 Offset 0 OpDecorate %27 DescriptorSet 0 OpDecorate %27 Binding 2 %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 4 %7 = OpTypeInt 32 0 %6 = OpConstant %7 10 -%5 = OpTypeArray %3 %6 +%5 = OpTypeArray %4 %6 %8 = OpTypeStruct %5 %10 = OpConstant %7 20 -%9 = OpTypeArray %3 %10 +%9 = OpTypeArray %4 %10 %11 = OpTypeStruct %9 -%12 = OpTypeImage %4 2D 0 1 0 1 Unknown +%12 = OpTypeImage %3 2D 0 1 0 1 Unknown %14 = OpConstant %7 30 -%13 = OpTypeArray %4 %14 +%13 = OpTypeArray %3 %14 %16 = OpConstant %7 40 -%15 = OpTypeArray %4 %16 -%18 = OpTypeInt 32 1 -%17 = OpTypeVector %18 2 +%15 = OpTypeArray %3 %16 +%17 = OpTypeInt 32 1 +%18 = OpTypeVector %17 2 %20 = OpConstant %7 2 -%19 = OpTypeArray %3 %20 +%19 = OpTypeArray %4 %20 %22 = OpTypeStruct %8 %23 = OpTypePointer StorageBuffer %22 %21 = OpVariable %23 StorageBuffer @@ -72,35 +72,35 @@ OpDecorate %27 Binding 2 %32 = OpTypePointer Private %15 %33 = OpConstantNull %15 %31 = OpVariable %32 Private %33 -%39 = OpTypeFunction %3 %17 %18 %18 +%39 = OpTypeFunction %4 %18 %17 %17 %40 = OpTypePointer StorageBuffer %8 %41 = OpConstant %7 0 %43 = OpTypePointer Uniform %11 -%46 = OpConstant %4 0.707 -%47 = OpConstant %4 0.0 -%48 = OpConstant %4 1.0 -%49 = OpConstantComposite %3 %46 %47 %47 %48 -%50 = OpConstantComposite %3 %47 %46 %47 %48 +%46 = OpConstant %3 0.707 +%47 = OpConstant %3 0.0 +%48 = OpConstant %3 1.0 +%49 = OpConstantComposite %4 %46 %47 %47 %48 +%50 = OpConstantComposite %4 %47 %46 %47 %48 %51 = OpConstantComposite %19 %49 %50 %53 = OpTypePointer Function %19 %55 = OpTypePointer StorageBuffer %5 -%56 = OpTypePointer StorageBuffer %3 +%56 = OpTypePointer StorageBuffer %4 %59 = OpTypePointer Uniform %9 -%60 = OpTypePointer Uniform %3 -%64 = OpTypeVector %18 3 +%60 = OpTypePointer Uniform %4 +%64 = OpTypeVector %17 3 %66 = OpTypeBool -%67 = OpConstantNull %3 +%67 = OpConstantNull %4 %73 = OpTypeVector %66 3 -%80 = OpTypePointer Workgroup %4 +%80 = OpTypePointer Workgroup %3 %81 = OpConstant %7 29 -%87 = OpTypePointer Private %4 +%87 = OpTypePointer Private %3 %88 = OpConstant %7 39 -%94 = OpTypePointer Function %3 +%94 = OpTypePointer Function %4 %95 = OpConstant %7 1 -%38 = OpFunction %3 None %39 -%35 = OpFunctionParameter %17 -%36 = OpFunctionParameter %18 -%37 = OpFunctionParameter %18 +%38 = OpFunction %4 None %39 +%35 = OpFunctionParameter %18 +%36 = OpFunctionParameter %17 +%37 = OpFunctionParameter %17 %34 = OpLabel %52 = OpVariable %53 Function %51 %42 = OpAccessChain %40 %21 %41 @@ -109,12 +109,12 @@ OpDecorate %27 Binding 2 OpBranch %54 %54 = OpLabel %57 = OpAccessChain %56 %42 %41 %36 -%58 = OpLoad %3 %57 +%58 = OpLoad %4 %57 %61 = OpAccessChain %60 %44 %41 %36 -%62 = OpLoad %3 %61 -%63 = OpFAdd %3 %58 %62 +%62 = OpLoad %4 %61 +%63 = OpFAdd %4 %58 %62 %65 = OpCompositeConstruct %64 %35 %36 -%68 = OpImageQueryLevels %18 %45 +%68 = OpImageQueryLevels %17 %45 %69 = OpULessThan %66 %37 %68 OpSelectionMerge %70 None OpBranchConditional %69 %71 %70 @@ -124,24 +124,24 @@ OpBranchConditional %69 %71 %70 %75 = OpAll %66 %74 OpBranchConditional %75 %76 %70 %76 = OpLabel -%77 = OpImageFetch %3 %45 %65 Lod %37 +%77 = OpImageFetch %4 %45 %65 Lod %37 OpBranch %70 %70 = OpLabel -%78 = OpPhi %3 %67 %54 %67 %71 %77 %76 -%79 = OpFAdd %3 %63 %78 +%78 = OpPhi %4 %67 %54 %67 %71 %77 %76 +%79 = OpFAdd %4 %63 %78 %82 = OpExtInst %7 %1 UMin %36 %81 %83 = OpAccessChain %80 %29 %82 -%84 = OpLoad %4 %83 -%85 = OpCompositeConstruct %3 %84 %84 %84 %84 -%86 = OpFAdd %3 %79 %85 +%84 = OpLoad %3 %83 +%85 = OpCompositeConstruct %4 %84 %84 %84 %84 +%86 = OpFAdd %4 %79 %85 %89 = OpExtInst %7 %1 UMin %36 %88 %90 = OpAccessChain %87 %31 %89 -%91 = OpLoad %4 %90 -%92 = OpCompositeConstruct %3 %91 %91 %91 %91 -%93 = OpFAdd %3 %86 %92 +%91 = OpLoad %3 %90 +%92 = OpCompositeConstruct %4 %91 %91 %91 %91 +%93 = OpFAdd %4 %86 %92 %96 = OpExtInst %7 %1 UMin %36 %95 %97 = OpAccessChain %94 %52 %96 -%98 = OpLoad %3 %97 -%99 = OpFAdd %3 %93 %98 +%98 = OpLoad %4 %97 +%99 = OpFAdd %4 %93 %98 OpReturnValue %99 OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/ray-query.spvasm b/naga/tests/out/spv/ray-query.spvasm index 328c820fea..8b784f2fa0 100644 --- a/naga/tests/out/spv/ray-query.spvasm +++ b/naga/tests/out/spv/ray-query.spvasm @@ -39,44 +39,44 @@ OpDecorate %17 Binding 1 OpDecorate %18 Block OpMemberDecorate %18 0 Offset 0 %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 3 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 3 %5 = OpTypeAccelerationStructureNV %6 = OpTypeInt 32 0 -%7 = OpTypeVector %4 2 +%7 = OpTypeVector %3 2 %8 = OpTypeBool -%9 = OpTypeMatrix %3 4 -%10 = OpTypeStruct %6 %4 %6 %6 %6 %6 %6 %7 %8 %9 %9 +%9 = OpTypeMatrix %4 4 +%10 = OpTypeStruct %6 %3 %6 %6 %6 %6 %6 %7 %8 %9 %9 %11 = OpTypeRayQueryKHR -%12 = OpTypeStruct %6 %6 %4 %4 %3 %3 -%13 = OpTypeStruct %6 %3 -%14 = OpTypeVector %4 4 +%12 = OpTypeStruct %6 %6 %3 %3 %4 %4 +%13 = OpTypeStruct %6 %4 +%14 = OpTypeVector %3 4 %16 = OpTypePointer UniformConstant %5 %15 = OpVariable %16 UniformConstant %18 = OpTypeStruct %13 %19 = OpTypePointer StorageBuffer %18 %17 = OpVariable %19 StorageBuffer -%26 = OpTypeFunction %10 %3 %3 %16 +%26 = OpTypeFunction %10 %4 %4 %16 %27 = OpConstant %6 4 %28 = OpConstant %6 255 -%29 = OpConstant %4 0.1 -%30 = OpConstant %4 100.0 +%29 = OpConstant %3 0.1 +%30 = OpConstant %3 100.0 %32 = OpTypePointer Function %11 %50 = OpConstant %6 1 -%67 = OpTypeFunction %3 %3 %10 -%68 = OpConstant %4 1.0 -%69 = OpConstant %4 2.4 -%70 = OpConstant %4 0.0 +%67 = OpTypeFunction %4 %4 %10 +%68 = OpConstant %3 1.0 +%69 = OpConstant %3 2.4 +%70 = OpConstant %3 0.0 %85 = OpTypeFunction %2 %87 = OpTypePointer StorageBuffer %13 %88 = OpConstant %6 0 -%90 = OpConstantComposite %3 %70 %70 %70 -%91 = OpConstantComposite %3 %70 %68 %70 +%90 = OpConstantComposite %4 %70 %70 %70 +%91 = OpConstantComposite %4 %70 %68 %70 %94 = OpTypePointer StorageBuffer %6 -%99 = OpTypePointer StorageBuffer %3 +%99 = OpTypePointer StorageBuffer %4 %25 = OpFunction %10 None %26 -%21 = OpFunctionParameter %3 -%22 = OpFunctionParameter %3 +%21 = OpFunctionParameter %4 +%22 = OpFunctionParameter %4 %23 = OpFunctionParameter %16 %20 = OpLabel %31 = OpVariable %32 Function @@ -86,10 +86,10 @@ OpBranch %33 %34 = OpCompositeConstruct %12 %27 %28 %29 %30 %21 %22 %35 = OpCompositeExtract %6 %34 0 %36 = OpCompositeExtract %6 %34 1 -%37 = OpCompositeExtract %4 %34 2 -%38 = OpCompositeExtract %4 %34 3 -%39 = OpCompositeExtract %3 %34 4 -%40 = OpCompositeExtract %3 %34 5 +%37 = OpCompositeExtract %3 %34 2 +%38 = OpCompositeExtract %3 %34 3 +%39 = OpCompositeExtract %4 %34 4 +%40 = OpCompositeExtract %4 %34 5 OpRayQueryInitializeKHR %31 %24 %35 %36 %39 %37 %40 %38 OpBranch %41 %41 = OpLabel @@ -116,7 +116,7 @@ OpBranch %41 %54 = OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR %6 %31 %50 %55 = OpRayQueryGetIntersectionGeometryIndexKHR %6 %31 %50 %56 = OpRayQueryGetIntersectionPrimitiveIndexKHR %6 %31 %50 -%57 = OpRayQueryGetIntersectionTKHR %4 %31 %50 +%57 = OpRayQueryGetIntersectionTKHR %3 %31 %50 %58 = OpRayQueryGetIntersectionBarycentricsKHR %7 %31 %50 %59 = OpRayQueryGetIntersectionFrontFaceKHR %8 %31 %50 %60 = OpRayQueryGetIntersectionObjectToWorldKHR %9 %31 %50 @@ -124,23 +124,23 @@ OpBranch %41 %62 = OpCompositeConstruct %10 %51 %57 %52 %53 %54 %55 %56 %58 %59 %60 %61 OpReturnValue %62 OpFunctionEnd -%66 = OpFunction %3 None %67 -%64 = OpFunctionParameter %3 +%66 = OpFunction %4 None %67 +%64 = OpFunctionParameter %4 %65 = OpFunctionParameter %10 %63 = OpLabel OpBranch %71 %71 = OpLabel %72 = OpCompositeExtract %9 %65 10 %73 = OpCompositeConstruct %14 %64 %68 -%74 = OpMatrixTimesVector %3 %72 %73 +%74 = OpMatrixTimesVector %4 %72 %73 %75 = OpVectorShuffle %7 %74 %74 0 1 %76 = OpExtInst %7 %1 Normalize %75 %77 = OpVectorTimesScalar %7 %76 %69 %78 = OpCompositeExtract %9 %65 9 %79 = OpCompositeConstruct %14 %77 %70 %68 -%80 = OpMatrixTimesVector %3 %78 %79 -%81 = OpFSub %3 %64 %80 -%82 = OpExtInst %3 %1 Normalize %81 +%80 = OpMatrixTimesVector %4 %78 %79 +%81 = OpFSub %4 %64 %80 +%82 = OpExtInst %4 %1 Normalize %81 OpReturnValue %82 OpFunctionEnd %84 = OpFunction %2 None %85 @@ -155,9 +155,9 @@ OpBranch %92 %97 = OpSelect %6 %96 %50 %88 %98 = OpAccessChain %94 %89 %88 OpStore %98 %97 -%100 = OpCompositeExtract %4 %93 1 -%101 = OpVectorTimesScalar %3 %91 %100 -%102 = OpFunctionCall %3 %66 %101 %93 +%100 = OpCompositeExtract %3 %93 1 +%101 = OpVectorTimesScalar %4 %91 %100 +%102 = OpFunctionCall %4 %66 %101 %93 %103 = OpAccessChain %99 %89 %50 OpStore %103 %102 OpReturn diff --git a/naga/tests/out/spv/shadow.spvasm b/naga/tests/out/spv/shadow.spvasm index 55bfa4fec0..d64bb2336b 100644 --- a/naga/tests/out/spv/shadow.spvasm +++ b/naga/tests/out/spv/shadow.spvasm @@ -108,26 +108,26 @@ OpDecorate %205 Location 0 OpDecorate %207 Location 1 OpDecorate %209 Location 0 %2 = OpTypeVoid -%5 = OpTypeFloat 32 -%4 = OpTypeVector %5 4 -%3 = OpTypeMatrix %4 4 -%7 = OpTypeInt 32 0 -%6 = OpTypeVector %7 4 -%8 = OpTypeStruct %3 %6 -%9 = OpTypeStruct %3 %4 -%10 = OpTypeVector %5 3 -%11 = OpTypeStruct %4 %10 %4 +%3 = OpTypeFloat 32 +%5 = OpTypeVector %3 4 +%4 = OpTypeMatrix %5 4 +%6 = OpTypeInt 32 0 +%7 = OpTypeVector %6 4 +%8 = OpTypeStruct %4 %7 +%9 = OpTypeStruct %4 %5 +%10 = OpTypeVector %3 3 +%11 = OpTypeStruct %5 %10 %5 %13 = OpTypeInt 32 1 %12 = OpTypeVector %13 4 %14 = OpTypeMatrix %10 3 -%15 = OpTypeStruct %3 %4 %4 +%15 = OpTypeStruct %4 %5 %5 %16 = OpTypeRuntimeArray %15 -%18 = OpConstant %7 10 +%18 = OpConstant %6 10 %17 = OpTypeArray %15 %18 -%19 = OpTypeImage %5 2D 1 1 0 1 Unknown +%19 = OpTypeImage %3 2D 1 1 0 1 Unknown %20 = OpTypeSampler -%21 = OpTypeVector %5 2 -%22 = OpConstant %5 0.05 +%21 = OpTypeVector %3 2 +%22 = OpConstant %3 0.05 %23 = OpConstantComposite %10 %22 %22 %22 %25 = OpTypeStruct %8 %26 = OpTypePointer Uniform %25 @@ -145,11 +145,11 @@ OpDecorate %209 Location 0 %36 = OpVariable %37 UniformConstant %39 = OpTypePointer UniformConstant %20 %38 = OpVariable %39 UniformConstant -%44 = OpTypeFunction %5 %7 %4 -%47 = OpConstant %5 0.0 -%48 = OpConstant %5 1.0 -%49 = OpConstant %5 0.5 -%50 = OpConstant %5 -0.5 +%44 = OpTypeFunction %3 %6 %5 +%47 = OpConstant %3 0.0 +%48 = OpConstant %3 1.0 +%49 = OpConstant %3 0.5 +%50 = OpConstant %3 -0.5 %51 = OpConstantComposite %21 %49 %50 %52 = OpConstantComposite %21 %49 %49 %55 = OpTypeBool @@ -157,70 +157,70 @@ OpDecorate %209 Location 0 %75 = OpTypePointer Input %12 %74 = OpVariable %75 Input %77 = OpVariable %75 Input -%80 = OpTypePointer Output %4 +%80 = OpTypePointer Output %5 %79 = OpVariable %80 Output %82 = OpTypePointer Output %10 %81 = OpVariable %82 Output %83 = OpVariable %80 Output %85 = OpTypeFunction %2 %86 = OpTypePointer Uniform %8 -%87 = OpConstant %7 0 +%87 = OpConstant %6 0 %89 = OpTypePointer Uniform %9 %92 = OpTypePointer Function %11 %93 = OpConstantNull %11 -%95 = OpTypePointer Uniform %3 +%95 = OpTypePointer Uniform %4 %102 = OpTypePointer Function %10 %110 = OpTypeVector %13 3 -%114 = OpConstant %7 1 -%116 = OpTypePointer Function %4 -%117 = OpConstant %7 2 -%125 = OpTypePointer Output %5 -%134 = OpTypePointer Input %4 +%114 = OpConstant %6 1 +%116 = OpTypePointer Function %5 +%117 = OpConstant %6 2 +%125 = OpTypePointer Output %3 +%134 = OpTypePointer Input %5 %133 = OpVariable %134 Input %137 = OpTypePointer Input %10 %136 = OpVariable %137 Input %139 = OpVariable %134 Input %141 = OpVariable %80 Output %145 = OpTypePointer StorageBuffer %16 -%151 = OpTypePointer Function %7 -%160 = OpTypePointer Uniform %6 -%161 = OpTypePointer Uniform %7 +%151 = OpTypePointer Function %6 +%160 = OpTypePointer Uniform %7 +%161 = OpTypePointer Uniform %6 %171 = OpTypePointer StorageBuffer %15 -%197 = OpTypePointer Uniform %4 +%197 = OpTypePointer Uniform %5 %203 = OpVariable %134 Input %205 = OpVariable %137 Input %207 = OpVariable %134 Input %209 = OpVariable %80 Output %213 = OpTypePointer Uniform %17 %236 = OpTypePointer Uniform %15 -%43 = OpFunction %5 None %44 -%41 = OpFunctionParameter %7 -%42 = OpFunctionParameter %4 +%43 = OpFunction %3 None %44 +%41 = OpFunctionParameter %6 +%42 = OpFunctionParameter %5 %40 = OpLabel %45 = OpLoad %19 %36 %46 = OpLoad %20 %38 OpBranch %53 %53 = OpLabel -%54 = OpCompositeExtract %5 %42 3 +%54 = OpCompositeExtract %3 %42 3 %56 = OpFOrdLessThanEqual %55 %54 %47 OpSelectionMerge %57 None OpBranchConditional %56 %58 %57 %58 = OpLabel OpReturnValue %48 %57 = OpLabel -%59 = OpCompositeExtract %5 %42 3 -%60 = OpFDiv %5 %48 %59 +%59 = OpCompositeExtract %3 %42 3 +%60 = OpFDiv %3 %48 %59 %61 = OpVectorShuffle %21 %42 %42 0 1 %62 = OpFMul %21 %61 %51 %63 = OpVectorTimesScalar %21 %62 %60 %64 = OpFAdd %21 %63 %52 %65 = OpBitcast %13 %41 -%66 = OpCompositeExtract %5 %42 2 -%67 = OpFMul %5 %66 %60 -%69 = OpConvertSToF %5 %65 +%66 = OpCompositeExtract %3 %42 2 +%67 = OpFMul %3 %66 %60 +%69 = OpConvertSToF %3 %65 %70 = OpCompositeConstruct %10 %64 %69 %71 = OpSampledImage %68 %45 %46 -%72 = OpImageSampleDrefExplicitLod %5 %71 %70 %67 Lod %47 +%72 = OpImageSampleDrefExplicitLod %3 %71 %70 %67 Lod %47 OpReturnValue %72 OpFunctionEnd %84 = OpFunction %2 None %85 @@ -233,16 +233,16 @@ OpFunctionEnd OpBranch %94 %94 = OpLabel %96 = OpAccessChain %95 %90 %87 -%97 = OpLoad %3 %96 +%97 = OpLoad %4 %96 %98 = OpAccessChain %95 %90 %87 -%99 = OpLoad %3 %98 -%100 = OpConvertSToF %4 %76 -%101 = OpMatrixTimesVector %4 %99 %100 -%103 = OpCompositeExtract %4 %97 0 +%99 = OpLoad %4 %98 +%100 = OpConvertSToF %5 %76 +%101 = OpMatrixTimesVector %5 %99 %100 +%103 = OpCompositeExtract %5 %97 0 %104 = OpVectorShuffle %10 %103 %103 0 1 2 -%105 = OpCompositeExtract %4 %97 1 +%105 = OpCompositeExtract %5 %97 1 %106 = OpVectorShuffle %10 %105 %105 0 1 2 -%107 = OpCompositeExtract %4 %97 2 +%107 = OpCompositeExtract %5 %97 2 %108 = OpVectorShuffle %10 %107 %107 0 1 2 %109 = OpCompositeConstruct %14 %104 %106 %108 %111 = OpVectorShuffle %110 %78 %78 0 1 2 @@ -253,20 +253,20 @@ OpStore %115 %113 %118 = OpAccessChain %116 %91 %117 OpStore %118 %101 %119 = OpAccessChain %95 %88 %87 -%120 = OpLoad %3 %119 -%121 = OpMatrixTimesVector %4 %120 %101 +%120 = OpLoad %4 %119 +%121 = OpMatrixTimesVector %5 %120 %101 %122 = OpAccessChain %116 %91 %87 OpStore %122 %121 %123 = OpLoad %11 %91 -%124 = OpCompositeExtract %4 %123 0 +%124 = OpCompositeExtract %5 %123 0 OpStore %79 %124 %126 = OpAccessChain %125 %79 %114 -%127 = OpLoad %5 %126 -%128 = OpFNegate %5 %127 +%127 = OpLoad %3 %126 +%128 = OpFNegate %3 %127 OpStore %126 %128 %129 = OpCompositeExtract %10 %123 1 OpStore %81 %129 -%130 = OpCompositeExtract %4 %123 2 +%130 = OpCompositeExtract %5 %123 2 OpStore %83 %130 OpReturn OpFunctionEnd @@ -274,9 +274,9 @@ OpFunctionEnd %131 = OpLabel %149 = OpVariable %102 Function %23 %150 = OpVariable %151 Function %87 -%135 = OpLoad %4 %133 +%135 = OpLoad %5 %133 %138 = OpLoad %10 %136 -%140 = OpLoad %4 %139 +%140 = OpLoad %5 %139 %132 = OpCompositeConstruct %11 %135 %138 %140 %143 = OpAccessChain %86 %24 %87 %144 = OpAccessChain %89 %27 %87 @@ -292,10 +292,10 @@ OpBranch %155 OpLoopMerge %156 %158 None OpBranch %157 %157 = OpLabel -%159 = OpLoad %7 %150 +%159 = OpLoad %6 %150 %162 = OpAccessChain %161 %143 %114 %87 -%163 = OpLoad %7 %162 -%164 = OpExtInst %7 %1 UMin %163 %18 +%163 = OpLoad %6 %162 +%164 = OpExtInst %6 %1 UMin %163 %18 %165 = OpULessThan %55 %159 %164 OpSelectionMerge %166 None OpBranchConditional %165 %166 %167 @@ -304,24 +304,24 @@ OpBranch %156 %166 = OpLabel OpBranch %168 %168 = OpLabel -%170 = OpLoad %7 %150 +%170 = OpLoad %6 %150 %172 = OpAccessChain %171 %146 %170 %173 = OpLoad %15 %172 -%174 = OpLoad %7 %150 -%175 = OpCompositeExtract %3 %173 0 -%176 = OpCompositeExtract %4 %132 2 -%177 = OpMatrixTimesVector %4 %175 %176 -%178 = OpFunctionCall %5 %43 %174 %177 -%179 = OpCompositeExtract %4 %173 1 +%174 = OpLoad %6 %150 +%175 = OpCompositeExtract %4 %173 0 +%176 = OpCompositeExtract %5 %132 2 +%177 = OpMatrixTimesVector %5 %175 %176 +%178 = OpFunctionCall %3 %43 %174 %177 +%179 = OpCompositeExtract %5 %173 1 %180 = OpVectorShuffle %10 %179 %179 0 1 2 -%181 = OpCompositeExtract %4 %132 2 +%181 = OpCompositeExtract %5 %132 2 %182 = OpVectorShuffle %10 %181 %181 0 1 2 %183 = OpFSub %10 %180 %182 %184 = OpExtInst %10 %1 Normalize %183 -%185 = OpDot %5 %154 %184 -%186 = OpExtInst %5 %1 FMax %47 %185 -%187 = OpFMul %5 %178 %186 -%188 = OpCompositeExtract %4 %173 2 +%185 = OpDot %3 %154 %184 +%186 = OpExtInst %3 %1 FMax %47 %185 +%187 = OpFMul %3 %178 %186 +%188 = OpCompositeExtract %5 %173 2 %189 = OpVectorShuffle %10 %188 %188 0 1 2 %190 = OpVectorTimesScalar %10 %189 %187 %191 = OpLoad %10 %149 @@ -331,16 +331,16 @@ OpBranch %169 %169 = OpLabel OpBranch %158 %158 = OpLabel -%193 = OpLoad %7 %150 -%194 = OpIAdd %7 %193 %114 +%193 = OpLoad %6 %150 +%194 = OpIAdd %6 %193 %114 OpStore %150 %194 OpBranch %155 %156 = OpLabel %195 = OpLoad %10 %149 -%196 = OpCompositeConstruct %4 %195 %48 +%196 = OpCompositeConstruct %5 %195 %48 %198 = OpAccessChain %197 %144 %114 -%199 = OpLoad %4 %198 -%200 = OpFMul %4 %196 %199 +%199 = OpLoad %5 %198 +%200 = OpFMul %5 %196 %199 OpStore %141 %200 OpReturn OpFunctionEnd @@ -348,9 +348,9 @@ OpFunctionEnd %201 = OpLabel %217 = OpVariable %102 Function %23 %218 = OpVariable %151 Function %87 -%204 = OpLoad %4 %203 +%204 = OpLoad %5 %203 %206 = OpLoad %10 %205 -%208 = OpLoad %4 %207 +%208 = OpLoad %5 %207 %202 = OpCompositeConstruct %11 %204 %206 %208 %211 = OpAccessChain %86 %24 %87 %212 = OpAccessChain %89 %27 %87 @@ -366,10 +366,10 @@ OpBranch %222 OpLoopMerge %223 %225 None OpBranch %224 %224 = OpLabel -%226 = OpLoad %7 %218 +%226 = OpLoad %6 %218 %227 = OpAccessChain %161 %211 %114 %87 -%228 = OpLoad %7 %227 -%229 = OpExtInst %7 %1 UMin %228 %18 +%228 = OpLoad %6 %227 +%229 = OpExtInst %6 %1 UMin %228 %18 %230 = OpULessThan %55 %226 %229 OpSelectionMerge %231 None OpBranchConditional %230 %231 %232 @@ -378,24 +378,24 @@ OpBranch %223 %231 = OpLabel OpBranch %233 %233 = OpLabel -%235 = OpLoad %7 %218 +%235 = OpLoad %6 %218 %237 = OpAccessChain %236 %214 %235 %238 = OpLoad %15 %237 -%239 = OpLoad %7 %218 -%240 = OpCompositeExtract %3 %238 0 -%241 = OpCompositeExtract %4 %202 2 -%242 = OpMatrixTimesVector %4 %240 %241 -%243 = OpFunctionCall %5 %43 %239 %242 -%244 = OpCompositeExtract %4 %238 1 +%239 = OpLoad %6 %218 +%240 = OpCompositeExtract %4 %238 0 +%241 = OpCompositeExtract %5 %202 2 +%242 = OpMatrixTimesVector %5 %240 %241 +%243 = OpFunctionCall %3 %43 %239 %242 +%244 = OpCompositeExtract %5 %238 1 %245 = OpVectorShuffle %10 %244 %244 0 1 2 -%246 = OpCompositeExtract %4 %202 2 +%246 = OpCompositeExtract %5 %202 2 %247 = OpVectorShuffle %10 %246 %246 0 1 2 %248 = OpFSub %10 %245 %247 %249 = OpExtInst %10 %1 Normalize %248 -%250 = OpDot %5 %221 %249 -%251 = OpExtInst %5 %1 FMax %47 %250 -%252 = OpFMul %5 %243 %251 -%253 = OpCompositeExtract %4 %238 2 +%250 = OpDot %3 %221 %249 +%251 = OpExtInst %3 %1 FMax %47 %250 +%252 = OpFMul %3 %243 %251 +%253 = OpCompositeExtract %5 %238 2 %254 = OpVectorShuffle %10 %253 %253 0 1 2 %255 = OpVectorTimesScalar %10 %254 %252 %256 = OpLoad %10 %217 @@ -405,16 +405,16 @@ OpBranch %234 %234 = OpLabel OpBranch %225 %225 = OpLabel -%258 = OpLoad %7 %218 -%259 = OpIAdd %7 %258 %114 +%258 = OpLoad %6 %218 +%259 = OpIAdd %6 %258 %114 OpStore %218 %259 OpBranch %222 %223 = OpLabel %260 = OpLoad %10 %217 -%261 = OpCompositeConstruct %4 %260 %48 +%261 = OpCompositeConstruct %5 %260 %48 %262 = OpAccessChain %197 %212 %114 -%263 = OpLoad %4 %262 -%264 = OpFMul %4 %261 %263 +%263 = OpLoad %5 %262 +%264 = OpFMul %5 %261 %263 OpStore %209 %264 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/struct-layout.spvasm b/naga/tests/out/spv/struct-layout.spvasm index fccaef5269..42899de9b5 100644 --- a/naga/tests/out/spv/struct-layout.spvasm +++ b/naga/tests/out/spv/struct-layout.spvasm @@ -52,11 +52,11 @@ OpDecorate %73 Location 1 OpDecorate %75 Location 2 OpDecorate %77 BuiltIn Position %2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 3 -%5 = OpTypeStruct %3 %4 -%6 = OpTypeVector %4 4 -%7 = OpTypeStruct %4 %3 %4 +%3 = OpTypeFloat 32 +%4 = OpTypeVector %3 3 +%5 = OpTypeStruct %4 %3 +%6 = OpTypeVector %3 4 +%7 = OpTypeStruct %3 %4 %3 %9 = OpTypeStruct %5 %10 = OpTypePointer Uniform %9 %8 = OpVariable %10 Uniform @@ -69,14 +69,14 @@ OpDecorate %77 BuiltIn Position %18 = OpTypeStruct %7 %19 = OpTypePointer StorageBuffer %18 %17 = OpVariable %19 StorageBuffer -%23 = OpTypePointer Input %3 +%23 = OpTypePointer Input %4 %22 = OpVariable %23 Input -%26 = OpTypePointer Input %4 +%26 = OpTypePointer Input %3 %25 = OpVariable %26 Input %29 = OpTypePointer Output %6 %28 = OpVariable %29 Output %31 = OpTypeFunction %2 -%32 = OpConstant %4 0.0 +%32 = OpConstant %3 0.0 %33 = OpConstantComposite %6 %32 %32 %32 %32 %37 = OpVariable %23 Input %39 = OpVariable %26 Input @@ -101,8 +101,8 @@ OpDecorate %77 BuiltIn Position %88 = OpConstantNull %7 %30 = OpFunction %2 None %31 %20 = OpLabel -%24 = OpLoad %3 %22 -%27 = OpLoad %4 %25 +%24 = OpLoad %4 %22 +%27 = OpLoad %3 %25 %21 = OpCompositeConstruct %5 %24 %27 OpBranch %34 %34 = OpLabel @@ -111,8 +111,8 @@ OpReturn OpFunctionEnd %42 = OpFunction %2 None %31 %35 = OpLabel -%38 = OpLoad %3 %37 -%40 = OpLoad %4 %39 +%38 = OpLoad %4 %37 +%40 = OpLoad %3 %39 %36 = OpCompositeConstruct %5 %38 %40 OpBranch %43 %43 = OpLabel @@ -134,9 +134,9 @@ OpReturn OpFunctionEnd %67 = OpFunction %2 None %31 %58 = OpLabel -%61 = OpLoad %4 %60 -%63 = OpLoad %3 %62 -%65 = OpLoad %4 %64 +%61 = OpLoad %3 %60 +%63 = OpLoad %4 %62 +%65 = OpLoad %3 %64 %59 = OpCompositeConstruct %7 %61 %63 %65 OpBranch %68 %68 = OpLabel @@ -145,9 +145,9 @@ OpReturn OpFunctionEnd %78 = OpFunction %2 None %31 %69 = OpLabel -%72 = OpLoad %4 %71 -%74 = OpLoad %3 %73 -%76 = OpLoad %4 %75 +%72 = OpLoad %3 %71 +%74 = OpLoad %4 %73 +%76 = OpLoad %3 %75 %70 = OpCompositeConstruct %7 %72 %74 %76 OpBranch %79 %79 = OpLabel diff --git a/naga/tests/out/wgsl/abstract-types-var.wgsl b/naga/tests/out/wgsl/abstract-types-var.wgsl index 0533f19442..596595ba44 100644 --- a/naga/tests/out/wgsl/abstract-types-var.wgsl +++ b/naga/tests/out/wgsl/abstract-types-var.wgsl @@ -22,6 +22,17 @@ var xafpaiai_1: array = array(1i, 2i); var xafpaiaf_1: array = array(1f, 2f); var xafpafai_1: array = array(1f, 2f); var xafpafaf_1: array = array(1f, 2f); +var ivispai: vec2 = vec2(1i); +var ivfspaf: vec2 = vec2(1f); +var ivis_ai: vec2 = vec2(1i); +var ivus_ai: vec2 = vec2(1u); +var ivfs_ai: vec2 = vec2(1f); +var ivfs_af: vec2 = vec2(1f); +var iafafaf: array = array(1f, 2f); +var iafaiai: array = array(1f, 2f); +var iafpafaf: array = array(1f, 2f); +var iafpaiaf: array = array(1f, 2f); +var iafpafai: array = array(1f, 2f); fn all_constant_arguments() { var xvipaiai: vec2 = vec2(42i, 43i); diff --git a/naga/tests/out/wgsl/binding-arrays.wgsl b/naga/tests/out/wgsl/binding-arrays.wgsl index 86bcfc1bff..5bed8ef007 100644 --- a/naga/tests/out/wgsl/binding-arrays.wgsl +++ b/naga/tests/out/wgsl/binding-arrays.wgsl @@ -34,8 +34,8 @@ fn main(fragment_in: FragmentIn) -> @location(0) vec4 { let uniform_index = uni.index; let non_uniform_index = fragment_in.index; - let uv = vec2(0f); - let pix = vec2(0i); + const uv = vec2(0f); + const pix = vec2(0i); let _e21 = textureDimensions(texture_array_unbounded[0]); let _e22 = u2_; u2_ = (_e22 + _e21); diff --git a/naga/tests/out/wgsl/const_assert.wgsl b/naga/tests/out/wgsl/const_assert.wgsl new file mode 100644 index 0000000000..fe1c1c02f4 --- /dev/null +++ b/naga/tests/out/wgsl/const_assert.wgsl @@ -0,0 +1,7 @@ +const x: i32 = 1i; +const y: i32 = 2i; + +fn foo() { + return; +} + diff --git a/naga/tests/out/wgsl/constructors.wgsl b/naga/tests/out/wgsl/constructors.wgsl index 0e5eec734a..6d9d7e2f5d 100644 --- a/naga/tests/out/wgsl/constructors.wgsl +++ b/naga/tests/out/wgsl/constructors.wgsl @@ -21,11 +21,11 @@ fn main() { var foo: Foo; foo = Foo(vec4(1f), 1i); - let m0_ = mat2x2(vec2(1f, 0f), vec2(0f, 1f)); - let m1_ = mat4x4(vec4(1f, 0f, 0f, 0f), vec4(0f, 1f, 0f, 0f), vec4(0f, 0f, 1f, 0f), vec4(0f, 0f, 0f, 1f)); - let cit0_ = vec2(0u); - let cit1_ = mat2x2(vec2(0f), vec2(0f)); - let cit2_ = array(0i, 1i, 2i, 3i); - let ic4_ = vec2(0u, 0u); - let ic5_ = mat2x3(vec3(0f, 0f, 0f), vec3(0f, 0f, 0f)); + const m0_ = mat2x2(vec2(1f, 0f), vec2(0f, 1f)); + const m1_ = mat4x4(vec4(1f, 0f, 0f, 0f), vec4(0f, 1f, 0f, 0f), vec4(0f, 0f, 1f, 0f), vec4(0f, 0f, 0f, 1f)); + const cit0_ = vec2(0u); + const cit1_ = mat2x2(vec2(0f), vec2(0f)); + const cit2_ = array(0i, 1i, 2i, 3i); + const ic4_ = vec2(0u, 0u); + const ic5_ = mat2x3(vec3(0f, 0f, 0f), vec3(0f, 0f, 0f)); } diff --git a/naga/tests/out/wgsl/cross.wgsl b/naga/tests/out/wgsl/cross.wgsl new file mode 100644 index 0000000000..2e213aa9c4 --- /dev/null +++ b/naga/tests/out/wgsl/cross.wgsl @@ -0,0 +1,4 @@ +@compute @workgroup_size(1, 1, 1) +fn main() { + let a = cross(vec3(0f, 1f, 2f), vec3(0f, 1f, 2f)); +} diff --git a/naga/tests/out/wgsl/expressions.frag.wgsl b/naga/tests/out/wgsl/expressions.frag.wgsl index 0ba5962ab2..ec53847d5f 100644 --- a/naga/tests/out/wgsl/expressions.frag.wgsl +++ b/naga/tests/out/wgsl/expressions.frag.wgsl @@ -268,12 +268,12 @@ fn testUnaryOpMat(a_16: mat3x3) { let _e3 = a_17; v_8 = -(_e3); let _e5 = a_17; - let _e7 = vec3(1f); + const _e7 = vec3(1f); let _e9 = (_e5 - mat3x3(_e7, _e7, _e7)); a_17 = _e9; v_8 = _e9; let _e10 = a_17; - let _e12 = vec3(1f); + const _e12 = vec3(1f); a_17 = (_e10 - mat3x3(_e12, _e12, _e12)); v_8 = _e10; return; diff --git a/naga/tests/out/wgsl/functions.wgsl b/naga/tests/out/wgsl/functions.wgsl index 79f000ce22..db7b81b146 100644 --- a/naga/tests/out/wgsl/functions.wgsl +++ b/naga/tests/out/wgsl/functions.wgsl @@ -1,16 +1,16 @@ fn test_fma() -> vec2 { - let a = vec2(2f, 2f); - let b = vec2(0.5f, 0.5f); - let c = vec2(0.5f, 0.5f); + const a = vec2(2f, 2f); + const b = vec2(0.5f, 0.5f); + const c = vec2(0.5f, 0.5f); return fma(a, b, c); } fn test_integer_dot_product() -> i32 { - let a_2_ = vec2(1i); - let b_2_ = vec2(1i); + const a_2_ = vec2(1i); + const b_2_ = vec2(1i); let c_2_ = dot(a_2_, b_2_); - let a_3_ = vec3(1u); - let b_3_ = vec3(1u); + const a_3_ = vec3(1u); + const b_3_ = vec3(1u); let c_3_ = dot(a_3_, b_3_); let c_4_ = dot(vec4(4i), vec4(2i)); return c_4_; diff --git a/naga/tests/out/wgsl/image.wgsl b/naga/tests/out/wgsl/image.wgsl index 008b4c20c1..a680e70aba 100644 --- a/naga/tests/out/wgsl/image.wgsl +++ b/naga/tests/out/wgsl/image.wgsl @@ -110,8 +110,8 @@ fn levels_queries() -> @builtin(position) vec4 { fn texture_sample() -> @location(0) vec4 { var a: vec4; - let tc = vec2(0.5f); - let tc3_ = vec3(0.5f); + const tc = vec2(0.5f); + const tc3_ = vec3(0.5f); let _e9 = textureSample(image_1d, sampler_reg, tc.x); let _e10 = a; a = (_e10 + _e9); @@ -186,8 +186,8 @@ fn texture_sample() -> @location(0) vec4 { fn texture_sample_comparison() -> @location(0) f32 { var a_1: f32; - let tc_1 = vec2(0.5f); - let tc3_1 = vec3(0.5f); + const tc_1 = vec2(0.5f); + const tc3_1 = vec3(0.5f); let _e8 = textureSampleCompare(image_2d_depth, sampler_cmp, tc_1, 0.5f); let _e9 = a_1; a_1 = (_e9 + _e8); @@ -218,7 +218,7 @@ fn texture_sample_comparison() -> @location(0) f32 { @fragment fn gather() -> @location(0) vec4 { - let tc_2 = vec2(0.5f); + const tc_2 = vec2(0.5f); let s2d = textureGather(1, image_2d, sampler_reg, tc_2); let s2d_offset = textureGather(3, image_2d, sampler_reg, tc_2, vec2(3i, 1i)); let s2d_depth = textureGatherCompare(image_2d_depth, sampler_cmp, tc_2, 0.5f); @@ -231,7 +231,7 @@ fn gather() -> @location(0) vec4 { @fragment fn depth_no_comparison() -> @location(0) vec4 { - let tc_3 = vec2(0.5f); + const tc_3 = vec2(0.5f); let s2d_1 = textureSample(image_2d_depth, sampler_reg, tc_3); let s2d_gather = textureGather(image_2d_depth, sampler_reg, tc_3); return (vec4(s2d_1) + s2d_gather); diff --git a/naga/tests/out/wgsl/interpolate.wgsl b/naga/tests/out/wgsl/interpolate.wgsl index 402e60cef5..adb90568e4 100644 --- a/naga/tests/out/wgsl/interpolate.wgsl +++ b/naga/tests/out/wgsl/interpolate.wgsl @@ -1,12 +1,16 @@ struct FragmentInput { @builtin(position) position: vec4, @location(0) @interpolate(flat) _flat: u32, - @location(1) @interpolate(linear) _linear: f32, - @location(2) @interpolate(linear, centroid) linear_centroid: vec2, - @location(3) @interpolate(linear, sample) linear_sample: vec3, - @location(4) perspective: vec4, - @location(5) @interpolate(perspective, centroid) perspective_centroid: f32, - @location(6) @interpolate(perspective, sample) perspective_sample: f32, + @location(1) @interpolate(flat, first) flat_first: u32, + @location(2) @interpolate(flat, either) flat_either: u32, + @location(3) @interpolate(linear) _linear: f32, + @location(4) @interpolate(linear, centroid) linear_centroid: vec2, + @location(6) @interpolate(linear, sample) linear_sample: vec3, + @location(7) @interpolate(linear) linear_center: vec3, + @location(8) perspective: vec4, + @location(9) @interpolate(perspective, centroid) perspective_centroid: f32, + @location(10) @interpolate(perspective, sample) perspective_sample: f32, + @location(11) perspective_center: f32, } @vertex @@ -15,14 +19,18 @@ fn vert_main() -> FragmentInput { out.position = vec4(2f, 4f, 5f, 6f); out._flat = 8u; + out.flat_first = 9u; + out.flat_either = 10u; out._linear = 27f; out.linear_centroid = vec2(64f, 125f); out.linear_sample = vec3(216f, 343f, 512f); + out.linear_center = vec3(255f, 511f, 1024f); out.perspective = vec4(729f, 1000f, 1331f, 1728f); out.perspective_centroid = 2197f; out.perspective_sample = 2744f; - let _e30 = out; - return _e30; + out.perspective_center = 2812f; + let _e41 = out; + return _e41; } @fragment diff --git a/naga/tests/out/wgsl/interpolate_compat.wgsl b/naga/tests/out/wgsl/interpolate_compat.wgsl new file mode 100644 index 0000000000..aeaac63547 --- /dev/null +++ b/naga/tests/out/wgsl/interpolate_compat.wgsl @@ -0,0 +1,37 @@ +struct FragmentInput { + @builtin(position) position: vec4, + @location(0) @interpolate(flat) _flat: u32, + @location(2) @interpolate(flat, either) flat_either: u32, + @location(3) @interpolate(linear) _linear: f32, + @location(4) @interpolate(linear, centroid) linear_centroid: vec2, + @location(6) @interpolate(linear, sample) linear_sample: vec3, + @location(7) @interpolate(linear) linear_center: vec3, + @location(8) perspective: vec4, + @location(9) @interpolate(perspective, centroid) perspective_centroid: f32, + @location(10) @interpolate(perspective, sample) perspective_sample: f32, + @location(11) perspective_center: f32, +} + +@vertex +fn vert_main() -> FragmentInput { + var out: FragmentInput; + + out.position = vec4(2f, 4f, 5f, 6f); + out._flat = 8u; + out.flat_either = 10u; + out._linear = 27f; + out.linear_centroid = vec2(64f, 125f); + out.linear_sample = vec3(216f, 343f, 512f); + out.linear_center = vec3(255f, 511f, 1024f); + out.perspective = vec4(729f, 1000f, 1331f, 1728f); + out.perspective_centroid = 2197f; + out.perspective_sample = 2744f; + out.perspective_center = 2812f; + let _e39 = out; + return _e39; +} + +@fragment +fn frag_main(val: FragmentInput) { + return; +} diff --git a/naga/tests/out/wgsl/local-const.wgsl b/naga/tests/out/wgsl/local-const.wgsl new file mode 100644 index 0000000000..587f5a8e54 --- /dev/null +++ b/naga/tests/out/wgsl/local-const.wgsl @@ -0,0 +1,11 @@ +const ga: i32 = 4i; +const gb: i32 = 4i; +const gc: u32 = 4u; +const gd: f32 = 4f; +const ge: vec3 = vec3(4i, 4i, 4i); +const gf: f32 = 2f; + +fn const_in_fn() { + const e = vec3(4i, 4i, 4i); +} + diff --git a/naga/tests/out/wgsl/math-functions.wgsl b/naga/tests/out/wgsl/math-functions.wgsl index 2271bb9cb0..732f7acdcf 100644 --- a/naga/tests/out/wgsl/math-functions.wgsl +++ b/naga/tests/out/wgsl/math-functions.wgsl @@ -1,25 +1,25 @@ @fragment fn main() { - let v = vec4(0f); + const v = vec4(0f); let a = degrees(1f); let b = radians(1f); let c = degrees(v); let d = radians(v); let e = saturate(v); let g = refract(v, v, 1f); - let sign_b = vec4(-1i, -1i, -1i, -1i); - let sign_d = vec4(-1f, -1f, -1f, -1f); + const sign_b = vec4(-1i, -1i, -1i, -1i); + const sign_d = vec4(-1f, -1f, -1f, -1f); let const_dot = dot(vec2(), vec2()); - let flb_b = vec2(-1i, -1i); - let flb_c = vec2(0u, 0u); - let ftb_c = vec2(0i, 0i); - let ftb_d = vec2(0u, 0u); - let ctz_e = vec2(32u, 32u); - let ctz_f = vec2(32i, 32i); - let ctz_g = vec2(0u, 0u); - let ctz_h = vec2(0i, 0i); - let clz_c = vec2(0i, 0i); - let clz_d = vec2(31u, 31u); + const flb_b = vec2(-1i, -1i); + const flb_c = vec2(0u, 0u); + const ftb_c = vec2(0i, 0i); + const ftb_d = vec2(0u, 0u); + const ctz_e = vec2(32u, 32u); + const ctz_f = vec2(32i, 32i); + const ctz_g = vec2(0u, 0u); + const ctz_h = vec2(0i, 0i); + const clz_c = vec2(0i, 0i); + const clz_d = vec2(31u, 31u); let lde_a = ldexp(1f, 2i); let lde_b = ldexp(vec2(1f, 2f), vec2(3i, 4i)); let modf_a = modf(1.5f); diff --git a/naga/tests/out/wgsl/operators.wgsl b/naga/tests/out/wgsl/operators.wgsl index dbf39556de..2194a01df1 100644 --- a/naga/tests/out/wgsl/operators.wgsl +++ b/naga/tests/out/wgsl/operators.wgsl @@ -11,7 +11,7 @@ fn builtins() -> vec4 { let m2_ = mix(v_f32_zero, v_f32_one, 0.1f); let b1_ = bitcast(1i); let b2_ = bitcast>(v_i32_one); - let v_i32_zero = vec4(0i, 0i, 0i, 0i); + const v_i32_zero = vec4(0i, 0i, 0i, 0i); return (((((vec4((vec4(s1_) + v_i32_zero)) + s2_) + m1_) + m2_) + vec4(b1_)) + b2_); } @@ -40,8 +40,8 @@ fn bool_cast(x: vec3) -> vec3 { } fn logical() { - let neg0_ = !(true); - let neg1_ = !(vec2(true)); + const neg0_ = !(true); + const neg1_ = !(vec2(true)); let or = (true || false); let and = (true && false); let bitwise_or0_ = (true | false); @@ -51,9 +51,9 @@ fn logical() { } fn arithmetic() { - let neg0_1 = -(1f); - let neg1_1 = -(vec2(1i)); - let neg2_ = -(vec2(1f)); + const neg0_1 = -(1f); + const neg1_1 = -(vec2(1i)); + const neg2_ = -(vec2(1f)); let add0_ = (2i + 1i); let add1_ = (2u + 1u); let add2_ = (2f + 1f); @@ -126,10 +126,10 @@ fn arithmetic() { } fn bit() { - let flip0_ = ~(1i); - let flip1_ = ~(1u); - let flip2_ = ~(vec2(1i)); - let flip3_ = ~(vec3(1u)); + const flip0_ = ~(1i); + const flip1_ = ~(1u); + const flip2_ = ~(vec2(1i)); + const flip3_ = ~(vec3(1u)); let or0_ = (2i | 1i); let or1_ = (2u | 1u); let or2_ = (vec2(2i) | vec2(1i)); @@ -230,14 +230,14 @@ fn assignment() { } fn negation_avoids_prefix_decrement() { - let p0_ = -(1i); - let p1_ = -(-(1i)); - let p2_ = -(-(1i)); - let p3_ = -(-(1i)); - let p4_ = -(-(-(1i))); - let p5_ = -(-(-(-(1i)))); - let p6_ = -(-(-(-(-(1i))))); - let p7_ = -(-(-(-(-(1i))))); + const p0_ = -(1i); + const p1_ = -(-(1i)); + const p2_ = -(-(1i)); + const p3_ = -(-(1i)); + const p4_ = -(-(-(1i))); + const p5_ = -(-(-(-(1i)))); + const p6_ = -(-(-(-(-(1i))))); + const p7_ = -(-(-(-(-(1i))))); } @compute @workgroup_size(1, 1, 1) diff --git a/naga/tests/out/wgsl/prepostfix.frag.wgsl b/naga/tests/out/wgsl/prepostfix.frag.wgsl index d2c59a0dd9..15916303bb 100644 --- a/naga/tests/out/wgsl/prepostfix.frag.wgsl +++ b/naga/tests/out/wgsl/prepostfix.frag.wgsl @@ -21,11 +21,11 @@ fn main_1() { vec = _e21; vec_target = _e21; let _e32 = mat; - let _e34 = vec3(1f); + const _e34 = vec3(1f); mat = (_e32 + mat4x3(_e34, _e34, _e34, _e34)); mat_target = _e32; let _e37 = mat; - let _e39 = vec3(1f); + const _e39 = vec3(1f); let _e41 = (_e37 - mat4x3(_e39, _e39, _e39, _e39)); mat = _e41; mat_target = _e41; diff --git a/naga/tests/out/wgsl/shadow.wgsl b/naga/tests/out/wgsl/shadow.wgsl index e9d5bbf1be..8b198d2ed1 100644 --- a/naga/tests/out/wgsl/shadow.wgsl +++ b/naga/tests/out/wgsl/shadow.wgsl @@ -40,7 +40,7 @@ fn fetch_shadow(light_id: u32, homogeneous_coords: vec4) -> f32 { if (homogeneous_coords.w <= 0f) { return 1f; } - let flip_correction = vec2(0.5f, -0.5f); + const flip_correction = vec2(0.5f, -0.5f); let proj_correction = (1f / homogeneous_coords.w); let light_local = (((homogeneous_coords.xy * flip_correction) * proj_correction) + vec2(0.5f, 0.5f)); let _e24 = textureSampleCompareLevel(t_shadow, sampler_shadow, light_local, i32(light_id), (homogeneous_coords.z * proj_correction)); diff --git a/naga/tests/out/wgsl/type-alias.wgsl b/naga/tests/out/wgsl/type-alias.wgsl index fe3cf79037..13bfcba82c 100644 --- a/naga/tests/out/wgsl/type-alias.wgsl +++ b/naga/tests/out/wgsl/type-alias.wgsl @@ -1,10 +1,10 @@ fn main() { - let a = vec3(0f, 0f, 0f); - let c = vec3(0f); - let b = vec3(vec2(0f), 0f); - let d = vec3(vec2(0f), 0f); - let e = vec3(d); - let f = mat2x2(vec2(1f, 2f), vec2(3f, 4f)); - let g = mat3x3(a, a, a); + const a = vec3(0f, 0f, 0f); + const c = vec3(0f); + const b = vec3(vec2(0f), 0f); + const d = vec3(vec2(0f), 0f); + const e = vec3(d); + const f = mat2x2(vec2(1f, 2f), vec2(3f, 4f)); + const g = mat3x3(a, a, a); } diff --git a/naga/tests/snapshots.rs b/naga/tests/snapshots.rs index 76fb293d5e..936203986d 100644 --- a/naga/tests/snapshots.rs +++ b/naga/tests/snapshots.rs @@ -14,8 +14,12 @@ const BASE_DIR_OUT: &str = "tests/out"; bitflags::bitflags! { #[derive(Clone, Copy)] struct Targets: u32 { + /// A serialization of the `naga::Module`, in RON format. const IR = 1; + + /// A serialization of the `naga::valid::ModuleInfo`, in RON format. const ANALYSIS = 1 << 1; + const SPIRV = 1 << 2; const METAL = 1 << 3; const GLSL = 1 << 4; @@ -354,6 +358,10 @@ fn check_targets( let debug_info = source_code.map(|code| naga::back::spv::DebugInfo { source_code: code, file_name: name.as_ref(), + // wgpu#6266: we technically know all the information here to + // produce the valid language but it's not too important for + // validation purposes + language: naga::back::spv::SourceLanguage::Unknown, }); if targets.contains(Targets::SPIRV) { @@ -745,6 +753,10 @@ fn convert_wgsl() { ("functions-webgl", Targets::GLSL), ( "interpolate", + Targets::SPIRV | Targets::METAL | Targets::HLSL | Targets::WGSL, + ), + ( + "interpolate_compat", Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::HLSL | Targets::WGSL, ), ( @@ -818,6 +830,7 @@ fn convert_wgsl() { "use-gl-ext-over-grad-workaround-if-instructed", Targets::GLSL, ), + ("local-const", Targets::IR | Targets::WGSL), ( "math-functions", Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::HLSL | Targets::WGSL, @@ -863,6 +876,7 @@ fn convert_wgsl() { "const-exprs", Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::HLSL | Targets::WGSL, ), + ("const_assert", Targets::WGSL | Targets::IR), ("separate-entry-points", Targets::SPIRV | Targets::GLSL), ( "struct-layout", @@ -910,6 +924,10 @@ fn convert_wgsl() { Targets::IR | Targets::SPIRV | Targets::METAL, ), ("vertex-pulling-transform", Targets::METAL), + ( + "cross", + Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::HLSL | Targets::WGSL, + ), ]; for &(name, targets) in inputs.iter() { diff --git a/naga/tests/validation.rs b/naga/tests/validation.rs index f64b408841..f20ae688b8 100644 --- a/naga/tests/validation.rs +++ b/naga/tests/validation.rs @@ -260,3 +260,239 @@ fn emit_workgroup_uniform_load_result() { variant(true).expect("module should validate"); assert!(variant(false).is_err()); } + +#[cfg(feature = "wgsl-in")] +#[test] +fn bad_cross_builtin_args() { + // NOTE: Things we expect to actually compile are in the `cross` snapshot test. + let cases = [ + ( + "vec2(0., 1.)", + "\ +error: Entry point main at Compute is invalid + ┌─ wgsl:3:13 + │ +3 │ let a = cross(vec2(0., 1.), vec2(0., 1.)); + │ ^^^^^ naga::Expression [6] + │ + = Expression [6] is invalid + = Argument [0] to Cross as expression [2] has an invalid type. + +", + ), + ( + "vec4(0., 1., 2., 3.)", + "\ +error: Entry point main at Compute is invalid + ┌─ wgsl:3:13 + │ +3 │ let a = cross(vec4(0., 1., 2., 3.), vec4(0., 1., 2., 3.)); + │ ^^^^^ naga::Expression [10] + │ + = Expression [10] is invalid + = Argument [0] to Cross as expression [4] has an invalid type. + +", + ), + ]; + + for (invalid_arg, expected_err) in cases { + let source = format!( + "\ +@compute @workgroup_size(1) +fn main() {{ + let a = cross({invalid_arg}, {invalid_arg}); +}} +" + ); + let module = naga::front::wgsl::parse_str(&source).unwrap(); + let err = valid::Validator::new(Default::default(), valid::Capabilities::all()) + .validate_no_overrides(&module) + .expect_err("module should be invalid"); + assert_eq!(err.emit_to_string(&source), expected_err); + } +} + +#[cfg(feature = "wgsl-in")] +#[test] +fn incompatible_interpolation_and_sampling_types() { + use dummy_interpolation_shader::DummyInterpolationShader; + + // NOTE: Things we expect to actually compile are in the `interpolate` snapshot test. + use itertools::Itertools; + + let invalid_shader_module = |interpolation_and_sampling| { + let (interpolation, sampling) = interpolation_and_sampling; + + let valid = matches!( + (interpolation, sampling), + (_, None) + | ( + naga::Interpolation::Perspective | naga::Interpolation::Linear, + Some( + naga::Sampling::Center | naga::Sampling::Centroid | naga::Sampling::Sample + ), + ) + | ( + naga::Interpolation::Flat, + Some(naga::Sampling::First | naga::Sampling::Either) + ) + ); + + if valid { + None + } else { + let DummyInterpolationShader { + source, + module, + interpolate_attr, + entry_point: _, + } = DummyInterpolationShader::new(interpolation, sampling); + Some(( + source, + module, + interpolation, + sampling.expect("default interpolation sampling should be valid"), + interpolate_attr, + )) + } + }; + + let invalid_cases = [ + naga::Interpolation::Flat, + naga::Interpolation::Linear, + naga::Interpolation::Perspective, + ] + .into_iter() + .cartesian_product( + [ + naga::Sampling::Either, + naga::Sampling::First, + naga::Sampling::Sample, + naga::Sampling::Center, + naga::Sampling::Centroid, + ] + .into_iter() + .map(Some) + .chain([None]), + ) + .filter_map(invalid_shader_module); + + for (invalid_source, invalid_module, interpolation, sampling, interpolate_attr) in invalid_cases + { + let err = valid::Validator::new(Default::default(), valid::Capabilities::all()) + .validate_no_overrides(&invalid_module) + .expect_err(&format!( + "module should be invalid for {interpolate_attr:?}" + )); + assert!(dbg!(err.emit_to_string(&invalid_source)).contains(&dbg!( + naga::valid::VaryingError::InvalidInterpolationSamplingCombination { + interpolation, + sampling, + } + .to_string() + )),); + } +} + +#[cfg(all(feature = "wgsl-in", feature = "glsl-out"))] +#[test] +fn no_flat_first_in_glsl() { + use dummy_interpolation_shader::DummyInterpolationShader; + + let DummyInterpolationShader { + source: _, + module, + interpolate_attr, + entry_point, + } = DummyInterpolationShader::new(naga::Interpolation::Flat, Some(naga::Sampling::First)); + + let mut validator = naga::valid::Validator::new(Default::default(), Default::default()); + let module_info = validator.validate(&module).unwrap(); + + let options = Default::default(); + let pipeline_options = naga::back::glsl::PipelineOptions { + shader_stage: naga::ShaderStage::Fragment, + entry_point: entry_point.to_owned(), + multiview: None, + }; + let mut glsl_writer = naga::back::glsl::Writer::new( + String::new(), + &module, + &module_info, + &options, + &pipeline_options, + Default::default(), + ) + .unwrap(); + + let err = glsl_writer.write().expect_err(&format!( + "`{interpolate_attr}` should fail backend validation" + )); + + assert!(matches!( + err, + naga::back::glsl::Error::FirstSamplingNotSupported + )); +} + +#[cfg(all(test, feature = "wgsl-in"))] +mod dummy_interpolation_shader { + pub struct DummyInterpolationShader { + pub source: String, + pub module: naga::Module, + pub interpolate_attr: String, + pub entry_point: &'static str, + } + + impl DummyInterpolationShader { + pub fn new(interpolation: naga::Interpolation, sampling: Option) -> Self { + // NOTE: If you have to add variants below, make sure to add them to the + // `cartesian_product`'d combinations in tests around here! + let interpolation_str = match interpolation { + naga::Interpolation::Flat => "flat", + naga::Interpolation::Linear => "linear", + naga::Interpolation::Perspective => "perspective", + }; + let sampling_str = match sampling { + None => String::new(), + Some(sampling) => format!( + ", {}", + match sampling { + naga::Sampling::First => "first", + naga::Sampling::Either => "either", + naga::Sampling::Center => "center", + naga::Sampling::Centroid => "centroid", + naga::Sampling::Sample => "sample", + } + ), + }; + let member_type = match interpolation { + naga::Interpolation::Perspective | naga::Interpolation::Linear => "f32", + naga::Interpolation::Flat => "u32", + }; + + let interpolate_attr = format!("@interpolate({interpolation_str}{sampling_str})"); + let source = format!( + "\ + struct VertexOutput {{ + @location(0) {interpolate_attr} member: {member_type}, +}} + +@fragment +fn main(input: VertexOutput) {{ + // ... +}} +" + ); + let module = naga::front::wgsl::parse_str(&source).unwrap(); + + Self { + source, + module, + interpolate_attr, + entry_point: "main", + } + } + } +} diff --git a/naga/tests/wgsl_errors.rs b/naga/tests/wgsl_errors.rs index d6d1710f77..2d91ba01cf 100644 --- a/naga/tests/wgsl_errors.rs +++ b/naga/tests/wgsl_errors.rs @@ -363,13 +363,13 @@ fn unknown_ident() { fn unknown_scalar_type() { check( r#" - const a: vec2; + const a = vec2(); "#, - r#"error: unknown scalar type: 'something' - ┌─ wgsl:2:27 + r#"error: unknown scalar type: 'vec2f' + ┌─ wgsl:2:28 │ -2 │ const a: vec2; - │ ^^^^^^^^^ unknown scalar type +2 │ const a = vec2(); + │ ^^^^^ unknown scalar type │ = note: Valid scalar types are f32, f64, i32, u32, bool @@ -833,13 +833,13 @@ fn matrix_with_bad_type() { check( r#" fn main() { - let m: mat3x3; + var m: mat3x3; } "#, r#"error: matrix scalar type must be floating-point, but found `i32` ┌─ wgsl:3:31 │ -3 │ let m: mat3x3; +3 │ var m: mat3x3; │ ^^^ must be floating-point (e.g. `f32`) "#, @@ -2277,3 +2277,166 @@ fn too_many_unclosed_loops() { .join() .unwrap() } + +#[test] +fn local_const_wrong_type() { + check( + " + fn f() { + const c: i32 = 5u; + } + ", + r###"error: the type of `c` is expected to be `i32`, but got `u32` + ┌─ wgsl:3:19 + │ +3 │ const c: i32 = 5u; + │ ^ definition of `c` + +"###, + ); +} + +#[test] +fn local_const_from_let() { + check( + " + fn f() { + let a = 5; + const c = a; + } + ", + r###"error: this operation is not supported in a const context + ┌─ wgsl:4:23 + │ +4 │ const c = a; + │ ^ operation not supported here + +"###, + ); +} + +#[test] +fn local_const_from_var() { + check( + " + fn f() { + var a = 5; + const c = a; + } + ", + r###"error: this operation is not supported in a const context + ┌─ wgsl:4:23 + │ +4 │ const c = a; + │ ^ operation not supported here + +"###, + ); +} + +#[test] +fn local_const_from_override() { + check( + " + override o: i32; + fn f() { + const c = o; + } + ", + r###"error: Unexpected override-expression + ┌─ wgsl:4:23 + │ +4 │ const c = o; + │ ^ see msg + +"###, + ); +} + +#[test] +fn local_const_from_global_var() { + check( + " + var v: i32; + fn f() { + const c = v; + } + ", + r###"error: Unexpected runtime-expression + ┌─ wgsl:4:23 + │ +4 │ const c = v; + │ ^ see msg + +"###, + ); +} + +#[test] +fn only_one_swizzle_type() { + check( + " + const ok1 = vec2(0.0, 0.0).xy; + const ok2 = vec2(0.0, 0.0).rg; + const err = vec2(0.0, 0.0).xg; + ", + r###"error: invalid field accessor `xg` + ┌─ wgsl:4:36 + │ +4 │ const err = vec2(0.0, 0.0).xg; + │ ^^ invalid accessor + +"###, + ); +} + +#[test] +fn const_assert_must_be_const() { + check( + " + fn foo() { + let a = 5; + const_assert a != 0; + } + ", + r###"error: this operation is not supported in a const context + ┌─ wgsl:4:26 + │ +4 │ const_assert a != 0; + │ ^ operation not supported here + +"###, + ); +} + +#[test] +fn const_assert_must_be_bool() { + check( + " + const_assert(5); // 5 is not bool + ", + r###"error: must be a const-expression that resolves to a bool + ┌─ wgsl:2:26 + │ +2 │ const_assert(5); // 5 is not bool + │ ^ must resolve to bool + +"###, + ); +} + +#[test] +fn const_assert_failed() { + check( + " + const_assert(false); + ", + r###"error: const_assert failure + ┌─ wgsl:2:26 + │ +2 │ const_assert(false); + │ ^^^^^ evaluates to false + +"###, + ); +} diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index 4726fe63a7..558eb194ba 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -56,7 +56,7 @@ fn main() { global.instance_create_surface( window.display_handle().unwrap().into(), window.window_handle().unwrap().into(), - Some(wgc::id::Id::zip(0, 1, wgt::Backend::Empty)), + Some(wgc::id::Id::zip(0, 1)), ) } .unwrap(); @@ -74,22 +74,23 @@ fn main() { #[cfg(not(feature = "winit"))] compatible_surface: None, }, - wgc::instance::AdapterInputs::IdSet(&[wgc::id::AdapterId::zip(0, 0, backend)]), + wgt::Backends::from(backend), + Some(wgc::id::AdapterId::zip(0, 1)), ) .expect("Unable to find an adapter for selected backend"); - let info = global.adapter_get_info(adapter).unwrap(); + let info = global.adapter_get_info(adapter); log::info!("Picked '{}'", info.name); - let device_id = wgc::id::Id::zip(1, 0, backend); - let queue_id = wgc::id::Id::zip(1, 0, backend); - let (_, _, error) = global.adapter_request_device( + let device_id = wgc::id::Id::zip(0, 1); + let queue_id = wgc::id::Id::zip(0, 1); + let res = global.adapter_request_device( adapter, &desc, None, Some(device_id), Some(queue_id), ); - if let Some(e) = error { + if let Err(e) = res { panic!("{:?}", e); } (device_id, queue_id) diff --git a/player/src/lib.rs b/player/src/lib.rs index c9ee55aa6d..df3aa89e1b 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -440,11 +440,7 @@ impl GlobalPlay for wgc::global::Global { let (encoder, error) = self.device_create_command_encoder( device, &wgt::CommandEncoderDescriptor { label: None }, - Some( - comb_manager - .process(device.backend()) - .into_command_encoder_id(), - ), + Some(comb_manager.process().into_command_encoder_id()), ); if let Some(e) = error { panic!("{e}"); diff --git a/player/tests/data/bind-group.ron b/player/tests/data/bind-group.ron index a53a77b16f..80a5d18ba7 100644 --- a/player/tests/data/bind-group.ron +++ b/player/tests/data/bind-group.ron @@ -2,13 +2,13 @@ features: [], expectations: [], //not crash! actions: [ - CreateBuffer(Id(0, 1, Empty), ( + CreateBuffer(Id(0, 1), ( label: None, size: 16, usage: 64, mapped_at_creation: false, )), - CreateBindGroupLayout(Id(0, 1, Empty), ( + CreateBindGroupLayout(Id(0, 1), ( label: None, entries: [ ( @@ -20,29 +20,29 @@ ), ], )), - CreateBindGroup(Id(0, 1, Empty), ( + CreateBindGroup(Id(0, 1), ( label: None, - layout: Id(0, 1, Empty), + layout: Id(0, 1), entries: [ ( binding: 0, resource: Buffer(( - buffer_id: Id(0, 1, Empty), + buffer_id: Id(0, 1), offset: 0, size: None, )), ) ], )), - CreatePipelineLayout(Id(0, 1, Empty), ( + CreatePipelineLayout(Id(0, 1), ( label: Some("empty"), bind_group_layouts: [ - Id(0, 1, Empty), + Id(0, 1), ], push_constant_ranges: [], )), CreateShaderModule( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, flags: (bits: 3), @@ -50,12 +50,12 @@ data: "empty.wgsl", ), CreateComputePipeline( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, - layout: Some(Id(0, 1, Empty)), + layout: Some(Id(0, 1)), stage: ( - module: Id(0, 1, Empty), + module: Id(0, 1), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -70,9 +70,9 @@ SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Id(0, 1, Empty), + bind_group_id: Some(Id(0, 1)), ), - SetPipeline(Id(0, 1, Empty)), + SetPipeline(Id(0, 1)), ], dynamic_offsets: [], string_data: [], diff --git a/player/tests/data/buffer-copy.ron b/player/tests/data/buffer-copy.ron index 5c66f2c019..0cce3b1f69 100644 --- a/player/tests/data/buffer-copy.ron +++ b/player/tests/data/buffer-copy.ron @@ -10,7 +10,7 @@ ], actions: [ CreateBuffer( - Id(0, 1, Empty), + Id(0, 1), ( label: Some("dummy"), size: 16, @@ -19,7 +19,7 @@ ), ), WriteBuffer( - id: Id(0, 1, Empty), + id: Id(0, 1), data: "data1.bin", range: ( start: 0, diff --git a/player/tests/data/clear-buffer-texture.ron b/player/tests/data/clear-buffer-texture.ron index 7b25fa42c5..4b7548d2fc 100644 --- a/player/tests/data/clear-buffer-texture.ron +++ b/player/tests/data/clear-buffer-texture.ron @@ -20,7 +20,7 @@ ) ], actions: [ - CreateTexture(Id(0, 1, Empty), ( + CreateTexture(Id(0, 1), ( label: Some("Output Texture"), size: ( width: 64, @@ -36,7 +36,7 @@ // First fill the texture to ensure it wasn't just zero initialized or "happened" to be zero. WriteTexture( to: ( - texture: Id(0, 1, Empty), + texture: Id(0, 1), mip_level: 0, array_layer: 0, ), @@ -52,7 +52,7 @@ ), ), CreateBuffer( - Id(0, 1, Empty), + Id(0, 1), ( label: Some("Output Buffer"), size: 16384, @@ -62,7 +62,7 @@ ), CreateBuffer( - Id(1, 1, Empty), + Id(1, 1), ( label: Some("Buffer to be cleared"), size: 16, @@ -72,7 +72,7 @@ ), // Make sure there is something in the buffer, otherwise it might be just zero init! WriteBuffer( - id: Id(1, 1, Empty), + id: Id(1, 1), data: "data1.bin", range: ( start: 0, @@ -82,7 +82,7 @@ ), Submit(1, [ ClearTexture( - dst: Id(0, 1, Empty), + dst: Id(0, 1), subresource_range: ImageSubresourceRange( aspect: all, baseMipLevel: 0, @@ -93,12 +93,12 @@ ), CopyTextureToBuffer( src: ( - texture: Id(0, 1, Empty), + texture: Id(0, 1), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1, Empty), + buffer: Id(0, 1), layout: ( offset: 0, bytes_per_row: Some(256), @@ -112,7 +112,7 @@ ), // Partial clear to prove ClearBuffer( - dst: Id(1, 1, Empty), + dst: Id(1, 1), offset: 4, size: Some(8), ) diff --git a/player/tests/data/pipeline-statistics-query.ron b/player/tests/data/pipeline-statistics-query.ron index 8a6e4239b9..17ef08b1bb 100644 --- a/player/tests/data/pipeline-statistics-query.ron +++ b/player/tests/data/pipeline-statistics-query.ron @@ -9,13 +9,13 @@ ), ], actions: [ - CreatePipelineLayout(Id(0, 1, Empty), ( + CreatePipelineLayout(Id(0, 1), ( label: Some("empty"), bind_group_layouts: [], push_constant_ranges: [], )), CreateShaderModule( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, flags: (bits: 3), @@ -23,12 +23,12 @@ data: "empty.wgsl", ), CreateComputePipeline( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, - layout: Some(Id(0, 1, Empty)), + layout: Some(Id(0, 1)), stage: ( - module: Id(0, 1, Empty), + module: Id(0, 1), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -37,7 +37,7 @@ ), ), CreateQuerySet( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: Some("Compute Invocation QuerySet"), count: 2, @@ -45,7 +45,7 @@ ), ), CreateBuffer( - Id(0, 1, Empty), + Id(0, 1), ( label: Some("Compute Invocation Result Buffer"), size: 16, @@ -57,9 +57,9 @@ RunComputePass( base: ( commands: [ - SetPipeline(Id(0, 1, Empty)), + SetPipeline(Id(0, 1)), BeginPipelineStatisticsQuery( - query_set_id: Id(0, 1, Empty), + query_set_id: Id(0, 1), query_index: 0, ), Dispatch((2, 3, 7,)), @@ -71,10 +71,10 @@ ), ), ResolveQuerySet( - query_set_id: Id(0, 1, Empty), + query_set_id: Id(0, 1), start_query: 0, query_count: 1, - destination: Id(0, 1, Empty), + destination: Id(0, 1), destination_offset: 0, ) ]), diff --git a/player/tests/data/quad.ron b/player/tests/data/quad.ron index aad576c42b..a954cb597f 100644 --- a/player/tests/data/quad.ron +++ b/player/tests/data/quad.ron @@ -10,14 +10,14 @@ ], actions: [ CreateShaderModule( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, flags: (bits: 3), ), data: "quad.wgsl", ), - CreateTexture(Id(0, 1, Empty), ( + CreateTexture(Id(0, 1), ( label: Some("Output Texture"), size: ( width: 64, @@ -31,12 +31,12 @@ view_formats: [], )), CreateTextureView( - id: Id(0, 1, Empty), - parent_id: Id(0, 1, Empty), + id: Id(0, 1), + parent_id: Id(0, 1), desc: (), ), CreateBuffer( - Id(0, 1, Empty), + Id(0, 1), ( label: Some("Output Buffer"), size: 16384, @@ -44,19 +44,19 @@ mapped_at_creation: false, ), ), - CreatePipelineLayout(Id(0, 1, Empty), ( + CreatePipelineLayout(Id(0, 1), ( label: None, bind_group_layouts: [], push_constant_ranges: [], )), CreateRenderPipeline( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, - layout: Some(Id(0, 1, Empty)), + layout: Some(Id(0, 1)), vertex: ( stage: ( - module: Id(0, 1, Empty), + module: Id(0, 1), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -66,7 +66,7 @@ ), fragment: Some(( stage: ( - module: Id(0, 1, Empty), + module: Id(0, 1), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -84,7 +84,7 @@ RunRenderPass( base: ( commands: [ - SetPipeline(Id(0, 1, Empty)), + SetPipeline(Id(0, 1)), Draw( vertex_count: 3, instance_count: 1, @@ -98,7 +98,7 @@ ), target_colors: [ Some(( - view: Id(0, 1, Empty), + view: Id(0, 1), resolve_target: None, channel: ( load_op: clear, @@ -117,12 +117,12 @@ ), CopyTextureToBuffer( src: ( - texture: Id(0, 1, Empty), + texture: Id(0, 1), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1, Empty), + buffer: Id(0, 1), layout: ( offset: 0, bytes_per_row: Some(256), diff --git a/player/tests/data/zero-init-buffer.ron b/player/tests/data/zero-init-buffer.ron index b13786e262..c4cf25f659 100644 --- a/player/tests/data/zero-init-buffer.ron +++ b/player/tests/data/zero-init-buffer.ron @@ -39,7 +39,7 @@ ], actions: [ CreateBuffer( - Id(0, 1, Empty), + Id(0, 1), ( label: Some("mapped_at_creation: false, with MAP_WRITE"), size: 16, @@ -48,7 +48,7 @@ ), ), CreateBuffer( - Id(1, 1, Empty), + Id(1, 1), ( label: Some("mapped_at_creation: false, without MAP_WRITE"), size: 16, @@ -57,7 +57,7 @@ ), ), CreateBuffer( - Id(2, 1, Empty), + Id(2, 1), ( label: Some("partially written"), size: 24, @@ -66,7 +66,7 @@ ), ), WriteBuffer( - id: Id(2, 1, Empty), + id: Id(2, 1), data: "data1.bin", range: ( start: 4, @@ -75,20 +75,20 @@ queued: true, ), CreateShaderModule( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, flags: (bits: 3), ), data: "zero-init-buffer-for-binding.wgsl", ), - CreateBuffer(Id(3, 1, Empty), ( + CreateBuffer(Id(3, 1), ( label: Some("used in binding"), size: 16, usage: 129, // STORAGE + MAP_READ mapped_at_creation: false, )), - CreateBindGroupLayout(Id(0, 1, Empty), ( + CreateBindGroupLayout(Id(0, 1), ( label: None, entries: [ ( @@ -105,34 +105,34 @@ ), ], )), - CreateBindGroup(Id(0, 1, Empty), ( + CreateBindGroup(Id(0, 1), ( label: None, - layout: Id(0, 1, Empty), + layout: Id(0, 1), entries: [ ( binding: 0, resource: Buffer(( - buffer_id: Id(3, 1, Empty), + buffer_id: Id(3, 1), offset: 0, size: Some(16), )), ), ], )), - CreatePipelineLayout(Id(0, 1, Empty), ( + CreatePipelineLayout(Id(0, 1), ( label: None, bind_group_layouts: [ - Id(0, 1, Empty), + Id(0, 1), ], push_constant_ranges: [], )), CreateComputePipeline( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, - layout: Some(Id(0, 1, Empty)), + layout: Some(Id(0, 1)), stage: ( - module: Id(0, 1, Empty), + module: Id(0, 1), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -145,11 +145,11 @@ base: ( label: None, commands: [ - SetPipeline(Id(0, 1, Empty)), + SetPipeline(Id(0, 1)), SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Id(0, 1, Empty), + bind_group_id: Some(Id(0, 1)), ), Dispatch((4, 1, 1)), ], diff --git a/player/tests/data/zero-init-texture-binding.ron b/player/tests/data/zero-init-texture-binding.ron index ba4951c198..48415f43c5 100644 --- a/player/tests/data/zero-init-texture-binding.ron +++ b/player/tests/data/zero-init-texture-binding.ron @@ -17,7 +17,7 @@ // MISSING: Partial views ], actions: [ - CreateTexture(Id(0, 1, Empty), ( + CreateTexture(Id(0, 1), ( label: Some("Sampled Texture"), size: ( width: 64, @@ -31,12 +31,12 @@ view_formats: [], )), CreateTextureView( - id: Id(0, 1, Empty), - parent_id: Id(0, 1, Empty), + id: Id(0, 1), + parent_id: Id(0, 1), desc: (), ), CreateBuffer( - Id(0, 1, Empty), + Id(0, 1), ( label: Some("Sampled Texture Buffer"), size: 16384, @@ -44,7 +44,7 @@ mapped_at_creation: false, ), ), - CreateTexture(Id(1, 1, Empty), ( + CreateTexture(Id(1, 1), ( label: Some("Storage Texture"), size: ( width: 64, @@ -58,12 +58,12 @@ view_formats: [], )), CreateTextureView( - id: Id(1, 1, Empty), - parent_id: Id(1, 1, Empty), + id: Id(1, 1), + parent_id: Id(1, 1), desc: (), ), CreateBuffer( - Id(1, 1, Empty), + Id(1, 1), ( label: Some("Storage Texture Buffer"), size: 16384, @@ -73,7 +73,7 @@ ), - CreateBindGroupLayout(Id(0, 1, Empty), ( + CreateBindGroupLayout(Id(0, 1), ( label: None, entries: [ ( @@ -98,29 +98,29 @@ ), ], )), - CreateBindGroup(Id(0, 1, Empty), ( + CreateBindGroup(Id(0, 1), ( label: None, - layout: Id(0, 1, Empty), + layout: Id(0, 1), entries: [ ( binding: 0, - resource: TextureView(Id(0, 1, Empty)), + resource: TextureView(Id(0, 1)), ), ( binding: 1, - resource: TextureView(Id(1, 1, Empty)), + resource: TextureView(Id(1, 1)), ), ], )), - CreatePipelineLayout(Id(0, 1, Empty), ( + CreatePipelineLayout(Id(0, 1), ( label: None, bind_group_layouts: [ - Id(0, 1, Empty), + Id(0, 1), ], push_constant_ranges: [], )), CreateShaderModule( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, flags: (bits: 3), @@ -128,12 +128,12 @@ data: "zero-init-texture-binding.wgsl", ), CreateComputePipeline( - id: Id(0, 1, Empty), + id: Id(0, 1), desc: ( label: None, - layout: Some(Id(0, 1, Empty)), + layout: Some(Id(0, 1)), stage: ( - module: Id(0, 1, Empty), + module: Id(0, 1), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -146,11 +146,11 @@ RunComputePass( base: ( commands: [ - SetPipeline(Id(0, 1, Empty)), + SetPipeline(Id(0, 1)), SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Id(0, 1, Empty), + bind_group_id: Some(Id(0, 1)), ), Dispatch((4, 1, 1)), ], @@ -161,12 +161,12 @@ ), CopyTextureToBuffer( src: ( - texture: Id(0, 1, Empty), + texture: Id(0, 1), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1, Empty), + buffer: Id(0, 1), layout: ( offset: 0, bytes_per_row: Some(256), @@ -180,12 +180,12 @@ ), CopyTextureToBuffer( src: ( - texture: Id(1, 1, Empty), + texture: Id(1, 1), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(1, 1, Empty), + buffer: Id(1, 1), layout: ( offset: 0, bytes_per_row: Some(256), diff --git a/player/tests/data/zero-init-texture-copytobuffer.ron b/player/tests/data/zero-init-texture-copytobuffer.ron index 599ddbd67d..eae95aaae4 100644 --- a/player/tests/data/zero-init-texture-copytobuffer.ron +++ b/player/tests/data/zero-init-texture-copytobuffer.ron @@ -10,7 +10,7 @@ // MISSING: Partial copies ], actions: [ - CreateTexture(Id(0, 1, Empty), ( + CreateTexture(Id(0, 1), ( label: Some("Copy To Buffer Texture"), size: ( width: 64, @@ -24,7 +24,7 @@ view_formats: [], )), CreateBuffer( - Id(0, 1, Empty), + Id(0, 1), ( label: Some("Copy to Buffer Buffer"), size: 16384, @@ -35,12 +35,12 @@ Submit(1, [ CopyTextureToBuffer( src: ( - texture: Id(0, 1, Empty), + texture: Id(0, 1), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1, Empty), + buffer: Id(0, 1), layout: ( offset: 0, bytes_per_row: Some(256), diff --git a/player/tests/data/zero-init-texture-rendertarget.ron b/player/tests/data/zero-init-texture-rendertarget.ron index ec844fe073..adbb869625 100644 --- a/player/tests/data/zero-init-texture-rendertarget.ron +++ b/player/tests/data/zero-init-texture-rendertarget.ron @@ -10,7 +10,7 @@ // MISSING: Partial view. ], actions: [ - CreateTexture(Id(0, 1, Empty), ( + CreateTexture(Id(0, 1), ( label: Some("Render Target Texture"), size: ( width: 64, @@ -24,12 +24,12 @@ view_formats: [], )), CreateTextureView( - id: Id(0, 1, Empty), - parent_id: Id(0, 1, Empty), + id: Id(0, 1), + parent_id: Id(0, 1), desc: (), ), CreateBuffer( - Id(0, 1, Empty), + Id(0, 1), ( label: Some("Render Target Buffer"), size: 16384, @@ -48,7 +48,7 @@ ), target_colors: [ Some(( - view: Id(0, 1, Empty), + view: Id(0, 1), resolve_target: None, channel: ( load_op: load, @@ -64,12 +64,12 @@ ), CopyTextureToBuffer( src: ( - texture: Id(0, 1, Empty), + texture: Id(0, 1), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1, Empty), + buffer: Id(0, 1), layout: ( offset: 0, bytes_per_row: Some(256), diff --git a/player/tests/test.rs b/player/tests/test.rs index ee8e2ecc0d..ec96f54469 100644 --- a/player/tests/test.rs +++ b/player/tests/test.rs @@ -14,6 +14,7 @@ use player::GlobalPlay; use std::{ fs::{read_to_string, File}, io::{Read, Seek, SeekFrom}, + mem::size_of, path::{Path, PathBuf}, slice, }; @@ -35,7 +36,7 @@ impl ExpectedData { fn len(&self) -> usize { match self { ExpectedData::Raw(vec) => vec.len(), - ExpectedData::U64(vec) => vec.len() * std::mem::size_of::(), + ExpectedData::U64(vec) => vec.len() * size_of::(), ExpectedData::File(_, size) => *size, } } @@ -104,10 +105,9 @@ impl Test<'_> { adapter: wgc::id::AdapterId, test_num: u32, ) { - let backend = adapter.backend(); - let device_id = wgc::id::Id::zip(test_num, 0, backend); - let queue_id = wgc::id::Id::zip(test_num, 0, backend); - let (_, _, error) = global.adapter_request_device( + let device_id = wgc::id::Id::zip(test_num, 1); + let queue_id = wgc::id::Id::zip(test_num, 1); + let res = global.adapter_request_device( adapter, &wgt::DeviceDescriptor { label: None, @@ -119,7 +119,7 @@ impl Test<'_> { Some(device_id), Some(queue_id), ); - if let Some(e) = error { + if let Err(e) = res { panic!("{:?}", e); } @@ -136,7 +136,7 @@ impl Test<'_> { } println!("\t\t\tMapping..."); for expect in &self.expectations { - let buffer = wgc::id::Id::zip(expect.buffer.index, expect.buffer.epoch, backend); + let buffer = wgc::id::Id::zip(expect.buffer.index, expect.buffer.epoch); global .buffer_map_async( buffer, @@ -159,7 +159,7 @@ impl Test<'_> { for expect in self.expectations { println!("\t\t\tChecking {}", expect.name); - let buffer = wgc::id::Id::zip(expect.buffer.index, expect.buffer.epoch, backend); + let buffer = wgc::id::Id::zip(expect.buffer.index, expect.buffer.epoch); let (ptr, size) = global .buffer_get_mapped_range( buffer, @@ -236,17 +236,18 @@ impl Corpus { force_fallback_adapter: false, compatible_surface: None, }, - wgc::instance::AdapterInputs::IdSet(&[wgc::id::Id::zip(0, 0, backend)]), + wgt::Backends::from(backend), + Some(wgc::id::Id::zip(0, 1)), ) { Ok(adapter) => adapter, Err(_) => continue, }; println!("\tBackend {:?}", backend); - let supported_features = global.adapter_features(adapter).unwrap(); - let downlevel_caps = global.adapter_downlevel_capabilities(adapter).unwrap(); + let supported_features = global.adapter_features(adapter); + let downlevel_caps = global.adapter_downlevel_capabilities(adapter); - let test = Test::load(dir.join(test_path), adapter.backend()); + let test = Test::load(dir.join(test_path), backend); if !supported_features.contains(test.features) { println!( "\t\tSkipped due to missing features {:?}", diff --git a/tests/src/image.rs b/tests/src/image.rs index e72d3ee442..602d93c4e2 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -377,7 +377,7 @@ fn copy_via_compute( let mut pass = encoder.begin_compute_pass(&ComputePassDescriptor::default()); pass.set_pipeline(&pipeline_copy); - pass.set_bind_group(0, &bg, &[]); + pass.set_bind_group(0, Some(&bg), &[]); pass.dispatch_workgroups(1, 1, 1); } diff --git a/tests/src/lib.rs b/tests/src/lib.rs index fcc1615875..89f7e91c6e 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -54,10 +54,16 @@ pub fn fail( } /// Run some code in an error scope and assert that validation succeeds. +#[track_caller] pub fn valid(device: &wgpu::Device, callback: impl FnOnce() -> T) -> T { device.push_error_scope(wgpu::ErrorFilter::Validation); let result = callback(); - assert!(pollster::block_on(device.pop_error_scope()).is_none()); + if let Some(error) = pollster::block_on(device.pop_error_scope()) { + panic!( + "`valid` block at {} encountered wgpu error:\n{error}", + std::panic::Location::caller() + ); + } result } diff --git a/tests/tests/bgra8unorm_storage.rs b/tests/tests/bgra8unorm_storage.rs index 0859473b2f..fa8310c7ea 100644 --- a/tests/tests/bgra8unorm_storage.rs +++ b/tests/tests/bgra8unorm_storage.rs @@ -110,7 +110,7 @@ static BGRA8_UNORM_STORAGE: GpuTestConfiguration = GpuTestConfiguration::new() timestamp_writes: None, }); - pass.set_bind_group(0, &bg, &[]); + pass.set_bind_group(0, Some(&bg), &[]); pass.set_pipeline(&pipeline); pass.dispatch_workgroups(256, 256, 1); } diff --git a/tests/tests/bind_group_layout_dedup.rs b/tests/tests/bind_group_layout_dedup.rs index 591f4f9054..f81360288f 100644 --- a/tests/tests/bind_group_layout_dedup.rs +++ b/tests/tests/bind_group_layout_dedup.rs @@ -31,129 +31,77 @@ static BIND_GROUP_LAYOUT_DEDUPLICATION: GpuTestConfiguration = GpuTestConfigurat .run_async(bgl_dedupe); async fn bgl_dedupe(ctx: TestingContext) { - let entries_1 = &[]; - - let entries_2 = &[ENTRY]; - - // Block so we can force all resource to die. - { - let bgl_1a = ctx - .device - .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: entries_1, - }); - - let bgl_2 = ctx - .device - .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: entries_2, - }); - - let bgl_1b = ctx - .device - .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: entries_1, - }); - - let bg_1a = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + let entries = &[]; + + let bgl_1a = ctx + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: None, - layout: &bgl_1a, - entries: &[], + entries, }); - let bg_1b = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + let bgl_1b = ctx + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: None, - layout: &bgl_1b, - entries: &[], + entries, }); - let pipeline_layout = ctx - .device - .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: None, - bind_group_layouts: &[&bgl_1b], - push_constant_ranges: &[], - }); - - let module = ctx - .device - .create_shader_module(wgpu::ShaderModuleDescriptor { - label: None, - source: wgpu::ShaderSource::Wgsl(SHADER_SRC.into()), - }); - - let desc = wgpu::ComputePipelineDescriptor { - label: None, - layout: Some(&pipeline_layout), - module: &module, - entry_point: Some("no_resources"), - compilation_options: Default::default(), - cache: None, - }; + let bg_1a = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &bgl_1a, + entries: &[], + }); - let pipeline = ctx.device.create_compute_pipeline(&desc); + let bg_1b = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &bgl_1b, + entries: &[], + }); - let mut encoder = ctx.device.create_command_encoder(&Default::default()); + let pipeline_layout = ctx + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&bgl_1b], + push_constant_ranges: &[], + }); - let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { + let module = ctx + .device + .create_shader_module(wgpu::ShaderModuleDescriptor { label: None, - timestamp_writes: None, + source: wgpu::ShaderSource::Wgsl(SHADER_SRC.into()), }); - pass.set_bind_group(0, &bg_1b, &[]); - pass.set_pipeline(&pipeline); - pass.dispatch_workgroups(1, 1, 1); + let desc = wgpu::ComputePipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + module: &module, + entry_point: Some("no_resources"), + compilation_options: Default::default(), + cache: None, + }; - pass.set_bind_group(0, &bg_1a, &[]); - pass.dispatch_workgroups(1, 1, 1); + let pipeline = ctx.device.create_compute_pipeline(&desc); - drop(pass); + let mut encoder = ctx.device.create_command_encoder(&Default::default()); - ctx.queue.submit(Some(encoder.finish())); + let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { + label: None, + timestamp_writes: None, + }); - // Abuse the fact that global_id is really just the bitpacked ids when targeting wgpu-core. - if ctx.adapter_info.backend != wgt::Backend::BrowserWebGpu { - let bgl_1a_idx = bgl_1a.global_id().inner() & 0xFFFF_FFFF; - assert_eq!(bgl_1a_idx, 0); - let bgl_2_idx = bgl_2.global_id().inner() & 0xFFFF_FFFF; - assert_eq!(bgl_2_idx, 1); - let bgl_1b_idx = bgl_1b.global_id().inner() & 0xFFFF_FFFF; - assert_eq!(bgl_1b_idx, 2); - } - } - - ctx.async_poll(wgpu::Maintain::wait()) - .await - .panic_on_timeout(); - - if ctx.adapter_info.backend != wgt::Backend::BrowserWebGpu { - // Indices are made reusable as soon as the handle is dropped so we keep them around - // for the duration of the loop. - let mut bgls = Vec::new(); - let mut indices = Vec::new(); - // Now all of the BGL ids should be dead, so we should get the same ids again. - for _ in 0..=2 { - let test_bgl = ctx - .device - .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: entries_1, - }); - - let test_bgl_idx = test_bgl.global_id().inner() & 0xFFFF_FFFF; - bgls.push(test_bgl); - indices.push(test_bgl_idx); - } - // We don't guarantee that the IDs will appear in the same order. Sort them - // and check that they all appear exactly once. - indices.sort(); - for (i, index) in indices.iter().enumerate() { - assert_eq!(*index, i as u64); - } - } + pass.set_bind_group(0, Some(&bg_1b), &[]); + pass.set_pipeline(&pipeline); + pass.dispatch_workgroups(1, 1, 1); + + pass.set_bind_group(0, Some(&bg_1a), &[]); + pass.dispatch_workgroups(1, 1, 1); + + drop(pass); + + ctx.queue.submit(Some(encoder.finish())); } #[gpu_test] @@ -231,7 +179,7 @@ fn bgl_dedupe_with_dropped_user_handle(ctx: TestingContext) { timestamp_writes: None, }); - pass.set_bind_group(0, &bg, &[]); + pass.set_bind_group(0, Some(&bg), &[]); pass.set_pipeline(&pipeline); pass.dispatch_workgroups(1, 1, 1); @@ -302,10 +250,10 @@ fn get_derived_bgl(ctx: TestingContext) { pass.set_pipeline(&pipeline); - pass.set_bind_group(0, &bg1, &[]); + pass.set_bind_group(0, Some(&bg1), &[]); pass.dispatch_workgroups(1, 1, 1); - pass.set_bind_group(0, &bg2, &[]); + pass.set_bind_group(0, Some(&bg2), &[]); pass.dispatch_workgroups(1, 1, 1); drop(pass); @@ -365,7 +313,7 @@ fn separate_pipelines_have_incompatible_derived_bgls(ctx: TestingContext) { pass.set_pipeline(&pipeline1); // We use the wrong bind group for this pipeline here. This should fail. - pass.set_bind_group(0, &bg2, &[]); + pass.set_bind_group(0, Some(&bg2), &[]); pass.dispatch_workgroups(1, 1, 1); fail( @@ -373,7 +321,7 @@ fn separate_pipelines_have_incompatible_derived_bgls(ctx: TestingContext) { || { drop(pass); }, - None, + Some("label at index 0 is not compatible with the corresponding bindgrouplayout"), ); } @@ -437,7 +385,7 @@ fn derived_bgls_incompatible_with_regular_bgls(ctx: TestingContext) { pass.set_pipeline(&pipeline); - pass.set_bind_group(0, &bg, &[]); + pass.set_bind_group(0, Some(&bg), &[]); pass.dispatch_workgroups(1, 1, 1); fail( @@ -445,7 +393,7 @@ fn derived_bgls_incompatible_with_regular_bgls(ctx: TestingContext) { || { drop(pass); }, - None, + Some("label at index 0 is not compatible with the corresponding bindgrouplayout"), ) } @@ -528,8 +476,8 @@ fn bgl_dedupe_derived(ctx: TestingContext) { timestamp_writes: None, }); pass.set_pipeline(&pipeline); - pass.set_bind_group(0, &bind_group_0, &[]); - pass.set_bind_group(1, &bind_group_1, &[]); + pass.set_bind_group(0, Some(&bind_group_0), &[]); + pass.set_bind_group(1, Some(&bind_group_1), &[]); pass.dispatch_workgroups(1, 1, 1); drop(pass); diff --git a/tests/tests/bind_groups.rs b/tests/tests/bind_groups.rs index fab1c065f0..607e852a7f 100644 --- a/tests/tests/bind_groups.rs +++ b/tests/tests/bind_groups.rs @@ -22,7 +22,7 @@ fn try_sampler_nonfiltering_layout( let sampler = ctx.device.create_sampler(descriptor); let create_bind_group = || { - ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + let _ = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { label, layout: &bind_group_layout, entries: &[wgpu::BindGroupEntry { diff --git a/tests/tests/buffer.rs b/tests/tests/buffer.rs index 77bc9e0640..f76a9fc352 100644 --- a/tests/tests/buffer.rs +++ b/tests/tests/buffer.rs @@ -220,7 +220,7 @@ static MINIMUM_BUFFER_BINDING_SIZE_LAYOUT: GpuTestConfiguration = GpuTestConfigu wgpu_test::fail( &ctx.device, || { - ctx.device + let _ = ctx.device .create_compute_pipeline(&wgpu::ComputePipelineDescriptor { label: None, layout: Some(&pipeline_layout), @@ -230,7 +230,7 @@ static MINIMUM_BUFFER_BINDING_SIZE_LAYOUT: GpuTestConfiguration = GpuTestConfigu cache: None, }); }, - None, + Some("shader global resourcebinding { group: 0, binding: 0 } is not available in the pipeline layout"), ); }); @@ -328,14 +328,14 @@ static MINIMUM_BUFFER_BINDING_SIZE_DISPATCH: GpuTestConfiguration = GpuTestConfi timestamp_writes: None, }); - pass.set_bind_group(0, &bind_group, &[]); + pass.set_bind_group(0, Some(&bind_group), &[]); pass.set_pipeline(&pipeline); pass.dispatch_workgroups(1, 1, 1); drop(pass); let _ = encoder.finish(); }, - None, + Some("buffer is bound with size 16 where the shader expects 32 in group[0] compact index 0"), ); }); diff --git a/tests/tests/buffer_copy.rs b/tests/tests/buffer_copy.rs index 698097f1b6..a7e9eff8cc 100644 --- a/tests/tests/buffer_copy.rs +++ b/tests/tests/buffer_copy.rs @@ -8,31 +8,62 @@ fn try_copy( ctx: &wgpu_test::TestingContext, offset: BufferAddress, size: BufferAddress, - should_fail: bool, + error_message: Option<&'static str>, ) { let buffer = ctx.device.create_buffer(&BUFFER_DESCRIPTOR); let data = vec![255; size as usize]; + fail_if( &ctx.device, - should_fail, + error_message.is_some(), || ctx.queue.write_buffer(&buffer, offset, &data), - None, + error_message, ); } #[gpu_test] static COPY_ALIGNMENT: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { - try_copy(&ctx, 0, 0, false); - try_copy(&ctx, 4, 16 + 1, true); - try_copy(&ctx, 64, 20 + 2, true); - try_copy(&ctx, 256, 44 + 3, true); - try_copy(&ctx, 1024, 8 + 4, false); - - try_copy(&ctx, 0, 4, false); - try_copy(&ctx, 4 + 1, 8, true); - try_copy(&ctx, 64 + 2, 12, true); - try_copy(&ctx, 256 + 3, 16, true); - try_copy(&ctx, 1024 + 4, 4, false); + try_copy(&ctx, 0, 0, None); + try_copy( + &ctx, + 4, + 16 + 1, + Some("copy size 17 does not respect `copy_buffer_alignment`"), + ); + try_copy( + &ctx, + 64, + 20 + 2, + Some("copy size 22 does not respect `copy_buffer_alignment`"), + ); + try_copy( + &ctx, + 256, + 44 + 3, + Some("copy size 47 does not respect `copy_buffer_alignment`"), + ); + try_copy(&ctx, 1024, 8 + 4, None); + + try_copy(&ctx, 0, 4, None); + try_copy( + &ctx, + 4 + 1, + 8, + Some("buffer offset 5 is not aligned to block size or `copy_buffer_alignment`"), + ); + try_copy( + &ctx, + 64 + 2, + 12, + Some("buffer offset 66 is not aligned to block size or `copy_buffer_alignment`"), + ); + try_copy( + &ctx, + 256 + 3, + 16, + Some("buffer offset 259 is not aligned to block size or `copy_buffer_alignment`"), + ); + try_copy(&ctx, 1024 + 4, 4, None); }); const BUFFER_SIZE: BufferAddress = 1234; diff --git a/tests/tests/buffer_usages.rs b/tests/tests/buffer_usages.rs index e0cadeed8a..00d63adae8 100644 --- a/tests/tests/buffer_usages.rs +++ b/tests/tests/buffer_usages.rs @@ -21,7 +21,8 @@ const NEEDS_MAPPABLE_PRIMARY_BUFFERS: &[Bu; 7] = &[ Bu::MAP_WRITE.union(Bu::MAP_READ), Bu::MAP_READ.union(Bu::COPY_DST.union(Bu::STORAGE)), Bu::MAP_WRITE.union(Bu::COPY_SRC.union(Bu::STORAGE)), - Bu::all(), + // these two require acceleration_structures feature + Bu::all().intersection(Bu::BLAS_INPUT.union(Bu::TLAS_INPUT).complement()), ]; const INVALID_BITS: Bu = Bu::from_bits_retain(0b1111111111111); const ALWAYS_FAIL: &[Bu; 2] = &[Bu::empty(), INVALID_BITS]; diff --git a/tests/tests/clear_texture.rs b/tests/tests/clear_texture.rs index f62e2be219..484681130b 100644 --- a/tests/tests/clear_texture.rs +++ b/tests/tests/clear_texture.rs @@ -26,7 +26,7 @@ static TEXTURE_FORMATS_UNCOMPRESSED_GLES_COMPAT: &[wgpu::TextureFormat] = &[ wgpu::TextureFormat::Bgra8UnormSrgb, wgpu::TextureFormat::Rgb10a2Uint, wgpu::TextureFormat::Rgb10a2Unorm, - wgpu::TextureFormat::Rg11b10UFloat, + wgpu::TextureFormat::Rg11b10Ufloat, wgpu::TextureFormat::Rg32Uint, wgpu::TextureFormat::Rg32Sint, wgpu::TextureFormat::Rg32Float, diff --git a/tests/tests/compute_pass_ownership.rs b/tests/tests/compute_pass_ownership.rs index 80f81f4d81..6b5bad8cf7 100644 --- a/tests/tests/compute_pass_ownership.rs +++ b/tests/tests/compute_pass_ownership.rs @@ -1,7 +1,7 @@ //! Tests that compute passes take ownership of resources that are associated with. //! I.e. once a resource is passed in to a compute pass, it can be dropped. -use std::num::NonZeroU64; +use std::{mem::size_of, num::NonZeroU64}; use wgpu::util::DeviceExt as _; use wgpu_test::{gpu_test, valid, GpuTestConfiguration, TestParameters, TestingContext}; @@ -45,7 +45,7 @@ async fn compute_pass_resource_ownership(ctx: TestingContext) { { let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default()); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups_indirect(&indirect_buffer, 0); // Now drop all resources we set. Then do a device poll to make sure the resources are really not dropped too early, no matter what. @@ -95,7 +95,7 @@ async fn compute_pass_query_set_ownership_pipeline_statistics(ctx: TestingContex { let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default()); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.begin_pipeline_statistics_query(&query_set, 0); cpass.dispatch_workgroups(1, 1, 1); cpass.end_pipeline_statistics_query(); @@ -153,7 +153,7 @@ async fn compute_pass_query_set_ownership_timestamps(ctx: TestingContext) { }), }); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.write_timestamp(&query_set_write_timestamp, 0); cpass.dispatch_workgroups(1, 1, 1); @@ -203,7 +203,7 @@ async fn compute_pass_keep_encoder_alive(ctx: TestingContext) { // Record some draw commands. cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups_indirect(&indirect_buffer, 0); // Dropping the pass will still execute the pass, even though there's no way to submit it. @@ -253,7 +253,7 @@ fn resource_setup(ctx: &TestingContext) -> ResourceSetup { source: wgpu::ShaderSource::Wgsl(SHADER_SRC.into()), }); - let buffer_size = 4 * std::mem::size_of::() as u64; + let buffer_size = 4 * size_of::() as u64; let bgl = ctx .device diff --git a/tests/tests/device.rs b/tests/tests/device.rs index d629f1b8e6..c832af06b4 100644 --- a/tests/tests/device.rs +++ b/tests/tests/device.rs @@ -36,32 +36,23 @@ static CROSS_DEVICE_BIND_GROUP_USAGE: GpuTestConfiguration = GpuTestConfiguratio #[gpu_test] static DEVICE_LIFETIME_CHECK: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default()) - .run_sync(|_| { - use pollster::FutureExt as _; - - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - backends: wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::all()), - dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(), - gles_minor_version: wgpu::util::gles_minor_version_from_env().unwrap_or_default(), - flags: wgpu::InstanceFlags::advanced_debugging().with_env(), - }); - - let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, None) - .block_on() - .expect("failed to create adapter"); - - let (device, queue) = adapter - .request_device(&wgpu::DeviceDescriptor::default(), None) - .block_on() - .expect("failed to create device"); + .run_sync(|ctx| { + ctx.instance.poll_all(false); - instance.poll_all(false); + let pre_report = ctx.instance.generate_report().unwrap(); - let pre_report = instance.generate_report().unwrap(); + let TestingContext { + instance, + device, + queue, + .. + } = ctx; drop(queue); drop(device); + let post_report = instance.generate_report().unwrap(); + assert_ne!( pre_report, post_report, "Queue and Device has not been dropped as expected" @@ -72,29 +63,16 @@ static DEVICE_LIFETIME_CHECK: GpuTestConfiguration = GpuTestConfiguration::new() #[gpu_test] static MULTIPLE_DEVICES: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default()) - .run_sync(|_| { + .run_sync(|ctx| { use pollster::FutureExt as _; - - fn create_device_and_queue() -> (wgpu::Device, wgpu::Queue) { - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - backends: wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::all()), - dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env() - .unwrap_or_default(), - gles_minor_version: wgpu::util::gles_minor_version_from_env().unwrap_or_default(), - flags: wgpu::InstanceFlags::advanced_debugging().with_env(), - }); - - let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, None) - .block_on() - .expect("failed to create adapter"); - - adapter - .request_device(&wgpu::DeviceDescriptor::default(), None) - .block_on() - .expect("failed to create device") - } - - let _ = vec![create_device_and_queue(), create_device_and_queue()]; + ctx.adapter + .request_device(&wgpu::DeviceDescriptor::default(), None) + .block_on() + .expect("failed to create device"); + ctx.adapter + .request_device(&wgpu::DeviceDescriptor::default(), None) + .block_on() + .expect("failed to create device"); }); #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] @@ -295,31 +273,32 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne fail( &ctx.device, || { - ctx.device + let _ = ctx + .device .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); }, - None, + Some("device with '' label is invalid"), ); // Creating a buffer should fail. fail( &ctx.device, || { - ctx.device.create_buffer(&wgpu::BufferDescriptor { + let _ = ctx.device.create_buffer(&wgpu::BufferDescriptor { label: None, size: 256, usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, mapped_at_creation: false, }); }, - None, + Some("device with '' label is invalid"), ); // Creating a texture should fail. fail( &ctx.device, || { - ctx.device.create_texture(&wgpu::TextureDescriptor { + let _ = ctx.device.create_texture(&wgpu::TextureDescriptor { label: None, size: wgpu::Extent3d { width: 512, @@ -334,7 +313,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne view_formats: &[], }); }, - None, + Some("device with '' label is invalid"), ); // Texture clear should fail. @@ -352,7 +331,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne }, ); }, - None, + Some("device with '' label is invalid"), ); // Creating a compute pass should fail. @@ -364,7 +343,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne timestamp_writes: None, }); }, - None, + Some("device with '' label is invalid"), ); // Creating a render pass should fail. @@ -383,7 +362,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne occlusion_query_set: None, }); }, - None, + Some("device with '' label is invalid"), ); // Copying a buffer to a buffer should fail. @@ -398,7 +377,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne 256, ); }, - None, + Some("device with '' label is invalid"), ); // Copying a buffer to a texture should fail. @@ -418,7 +397,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne texture_extent, ); }, - None, + Some("device with '' label is invalid"), ); // Copying a texture to a buffer should fail. @@ -438,7 +417,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne texture_extent, ); }, - None, + Some("device with '' label is invalid"), ); // Copying a texture to a texture should fail. @@ -451,27 +430,28 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne texture_extent, ); }, - None, + Some("device with '' label is invalid"), ); // Creating a bind group layout should fail. fail( &ctx.device, || { - ctx.device + let _ = ctx + .device .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: None, entries: &[], }); }, - None, + Some("device with '' label is invalid"), ); // Creating a bind group should fail. fail( &ctx.device, || { - ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + let _ = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { label: None, layout: &bind_group_layout, entries: &[wgpu::BindGroupEntry { @@ -482,54 +462,58 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne }], }); }, - None, + Some("device with '' label is invalid"), ); // Creating a pipeline layout should fail. fail( &ctx.device, || { - ctx.device + let _ = ctx + .device .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: None, bind_group_layouts: &[], push_constant_ranges: &[], }); }, - None, + Some("device with '' label is invalid"), ); // Creating a shader module should fail. fail( &ctx.device, || { - ctx.device + let _ = ctx + .device .create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed("")), }); }, - None, + Some("device with '' label is invalid"), ); // Creating a shader module spirv should fail. fail( &ctx.device, || unsafe { - ctx.device + let _ = ctx + .device .create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV { label: None, source: std::borrow::Cow::Borrowed(&[]), }); }, - None, + Some("device with '' label is invalid"), ); // Creating a render pipeline should fail. fail( &ctx.device, || { - ctx.device + let _ = ctx + .device .create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: None, layout: None, @@ -547,14 +531,15 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne cache: None, }); }, - None, + Some("device with '' label is invalid"), ); // Creating a compute pipeline should fail. fail( &ctx.device, || { - ctx.device + let _ = ctx + .device .create_compute_pipeline(&wgpu::ComputePipelineDescriptor { label: None, layout: None, @@ -564,14 +549,15 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne cache: None, }); }, - None, + Some("device with '' label is invalid"), ); // Creating a compute pipeline should fail. fail( &ctx.device, || { - ctx.device + let _ = ctx + .device .create_compute_pipeline(&wgpu::ComputePipelineDescriptor { label: None, layout: None, @@ -581,7 +567,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne cache: None, }); }, - None, + Some("device with '' label is invalid"), ); // Buffer map should fail. @@ -592,7 +578,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne .slice(..) .map_async(wgpu::MapMode::Write, |_| ()); }, - None, + Some("device with '' label is invalid"), ); // Buffer unmap should fail. @@ -601,7 +587,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne || { buffer_for_unmap.unmap(); }, - None, + Some("device with '' label is invalid"), ); }); @@ -665,33 +651,6 @@ static DEVICE_DROP_THEN_LOST: GpuTestConfiguration = GpuTestConfiguration::new() ); }); -#[gpu_test] -static DEVICE_INVALID_THEN_SET_LOST_CALLBACK: GpuTestConfiguration = GpuTestConfiguration::new() - .parameters(TestParameters::default().expect_fail(FailureCase::webgl2())) - .run_sync(|ctx| { - // This test checks that when the device is invalid, a subsequent call - // to set the device lost callback will immediately call the callback. - // Invalidating the device is done via a testing-only method. Fails on - // webgl because webgl doesn't implement make_invalid. - - // Make the device invalid. - ctx.device.make_invalid(); - - static WAS_CALLED: AtomicBool = AtomicBool::new(false); - - // Set a LoseDeviceCallback on the device. - let callback = Box::new(|reason, _m| { - WAS_CALLED.store(true, std::sync::atomic::Ordering::SeqCst); - assert_eq!(reason, wgt::DeviceLostReason::DeviceInvalid); - }); - ctx.device.set_device_lost_callback(callback); - - assert!( - WAS_CALLED.load(std::sync::atomic::Ordering::SeqCst), - "Device lost callback should have been called." - ); - }); - #[gpu_test] static DEVICE_LOST_REPLACED_CALLBACK: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default()) @@ -852,7 +811,7 @@ static DIFFERENT_BGL_ORDER_BW_SHADER_AND_API: GpuTestConfiguration = GpuTestConf // fail(&ctx.device, || { // }, ""); - ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + let _ = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { label: None, layout: &render_pipeline.get_bind_group_layout(0), entries: &[ diff --git a/tests/tests/encoder.rs b/tests/tests/encoder.rs index e4755dcd74..0be5efb901 100644 --- a/tests/tests/encoder.rs +++ b/tests/tests/encoder.rs @@ -68,7 +68,7 @@ static DROP_ENCODER_AFTER_ERROR: GpuTestConfiguration = GpuTestConfiguration::ne renderpass.set_viewport(0.0, 0.0, -1.0, -1.0, 0.0, 1.0); drop(renderpass); }, - None, + Some("viewport has invalid rect"), ); // This is the actual interesting error condition. We've created diff --git a/tests/tests/float32_filterable.rs b/tests/tests/float32_filterable.rs index ee288ac799..cc1ccd5a2a 100644 --- a/tests/tests/float32_filterable.rs +++ b/tests/tests/float32_filterable.rs @@ -63,7 +63,7 @@ static FLOAT32_FILTERABLE_WITHOUT_FEATURE: GpuTestConfiguration = GpuTestConfigu || { create_texture_binding(device, wgpu::TextureFormat::R32Float, true); }, - None, + Some("texture binding 0 expects sample type = float { filterable: true }, but given a view with format = r32float"), ); }); diff --git a/tests/tests/life_cycle.rs b/tests/tests/life_cycle.rs index e959743a59..d8d21940c8 100644 --- a/tests/tests/life_cycle.rs +++ b/tests/tests/life_cycle.rs @@ -4,7 +4,7 @@ use wgpu_test::{fail, gpu_test, GpuTestConfiguration}; static BUFFER_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_async(|ctx| async move { let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { - label: None, + label: Some("buffer"), size: 256, usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, mapped_at_creation: false, @@ -25,7 +25,7 @@ static BUFFER_DESTROY: GpuTestConfiguration = .slice(..) .map_async(wgpu::MapMode::Write, move |_| {}); }, - None, + Some("buffer with 'buffer' label has been destroyed"), ); buffer.destroy(); diff --git a/tests/tests/mem_leaks.rs b/tests/tests/mem_leaks.rs index 75de0776e8..84879efda3 100644 --- a/tests/tests/mem_leaks.rs +++ b/tests/tests/mem_leaks.rs @@ -194,7 +194,7 @@ async fn draw_test_with_reports( }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bg, &[]); + rpass.set_bind_group(0, Some(&bg), &[]); let global_report = ctx.instance.generate_report().unwrap(); let report = global_report.hub_report(); diff --git a/tests/tests/nv12_texture/mod.rs b/tests/tests/nv12_texture/mod.rs index 2f149d0148..d6af8496f7 100644 --- a/tests/tests/nv12_texture/mod.rs +++ b/tests/tests/nv12_texture/mod.rs @@ -115,7 +115,7 @@ static NV12_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfigurati occlusion_query_set: None, }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.draw(0..4, 0..1); drop(rpass); ctx.queue.submit(Some(encoder.finish())); @@ -149,7 +149,7 @@ static NV12_TEXTURE_VIEW_PLANE_ON_NON_PLANAR_FORMAT: GpuTestConfiguration = ..Default::default() }); }, - None, + Some("aspect plane0 is not in the source texture format r8unorm"), ); }); @@ -181,7 +181,7 @@ static NV12_TEXTURE_VIEW_PLANE_OUT_OF_BOUNDS: GpuTestConfiguration = GpuTestConf ..Default::default() }); }, - None, + Some("aspect plane2 is not in the source texture format nv12"), ); }); @@ -213,7 +213,7 @@ static NV12_TEXTURE_BAD_FORMAT_VIEW_PLANE: GpuTestConfiguration = GpuTestConfigu ..Default::default() }); }, - None, + Some("unable to view texture nv12 as rg8unorm"), ); }); @@ -241,6 +241,6 @@ static NV12_TEXTURE_BAD_SIZE: GpuTestConfiguration = GpuTestConfiguration::new() view_formats: &[], }); }, - None, + Some("width 255 is not a multiple of nv12's width multiple requirement"), ); }); diff --git a/tests/tests/occlusion_query/mod.rs b/tests/tests/occlusion_query/mod.rs index a9b1f12649..20c7fff82b 100644 --- a/tests/tests/occlusion_query/mod.rs +++ b/tests/tests/occlusion_query/mod.rs @@ -1,4 +1,4 @@ -use std::borrow::Cow; +use std::{borrow::Cow, mem::size_of}; use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters}; #[gpu_test] @@ -100,7 +100,7 @@ static OCCLUSION_QUERY: GpuTestConfiguration = GpuTestConfiguration::new() // Resolve query set to buffer let query_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { label: Some("Query buffer"), - size: std::mem::size_of::() as u64 * 3, + size: size_of::() as u64 * 3, usage: wgpu::BufferUsages::QUERY_RESOLVE | wgpu::BufferUsages::COPY_SRC, mapped_at_creation: false, }); diff --git a/tests/tests/partially_bounded_arrays/mod.rs b/tests/tests/partially_bounded_arrays/mod.rs index 195fd88dd4..4e6d6fc097 100644 --- a/tests/tests/partially_bounded_arrays/mod.rs +++ b/tests/tests/partially_bounded_arrays/mod.rs @@ -90,7 +90,7 @@ static PARTIALLY_BOUNDED_ARRAY: GpuTestConfiguration = GpuTestConfiguration::new timestamp_writes: None, }); cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups(1, 1, 1); } diff --git a/tests/tests/pipeline.rs b/tests/tests/pipeline.rs index 3cf8d13dfe..f7d8d1ec7b 100644 --- a/tests/tests/pipeline.rs +++ b/tests/tests/pipeline.rs @@ -8,7 +8,7 @@ static PIPELINE_DEFAULT_LAYOUT_BAD_MODULE: GpuTestConfiguration = GpuTestConfigu .parameters( TestParameters::default() // https://github.com/gfx-rs/wgpu/issues/4167 - .expect_fail(FailureCase::always().panic("Pipeline is invalid")), + .expect_fail(FailureCase::always().panic("Error reflecting bind group")), ) .run_sync(|ctx| { ctx.device.push_error_scope(wgpu::ErrorFilter::Validation); @@ -58,7 +58,8 @@ static NO_TARGETLESS_RENDER: GpuTestConfiguration = GpuTestConfiguration::new() // tries to compile code in an unsupported multisample count. Failing to validate here // has historically resulted in requesting the back end to compile code. for power_of_two in [1, 2, 4, 8, 16, 32, 64] { - ctx.device + let _ = ctx + .device .create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: None, layout: None, diff --git a/tests/tests/pipeline_cache.rs b/tests/tests/pipeline_cache.rs index 67e9e68270..c88a871c75 100644 --- a/tests/tests/pipeline_cache.rs +++ b/tests/tests/pipeline_cache.rs @@ -32,7 +32,7 @@ fn shader() -> String { r#" @group(0) @binding(0) var output: array; - + @compute @workgroup_size(1) fn main() {{ {body} @@ -167,7 +167,7 @@ async fn validate_pipeline( timestamp_writes: None, }); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, bind_group, &[]); + cpass.set_bind_group(0, Some(bind_group), &[]); cpass.dispatch_workgroups(1, 1, 1); } diff --git a/tests/tests/poll.rs b/tests/tests/poll.rs index 7e99cbcd7d..aeea2617f6 100644 --- a/tests/tests/poll.rs +++ b/tests/tests/poll.rs @@ -46,7 +46,7 @@ fn generate_dummy_work(ctx: &TestingContext) -> CommandBuffer { .create_command_encoder(&CommandEncoderDescriptor::default()); let mut cpass = cmd_buf.begin_compute_pass(&ComputePassDescriptor::default()); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); drop(cpass); cmd_buf.finish() diff --git a/tests/tests/push_constants.rs b/tests/tests/push_constants.rs index 905578d533..047fe5c8f2 100644 --- a/tests/tests/push_constants.rs +++ b/tests/tests/push_constants.rs @@ -119,7 +119,7 @@ async fn partial_update_test(ctx: TestingContext) { timestamp_writes: None, }); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); // -- Dispatch 0 -- diff --git a/tests/tests/queue_transfer.rs b/tests/tests/queue_transfer.rs index 79a79e0ecf..6f816374cb 100644 --- a/tests/tests/queue_transfer.rs +++ b/tests/tests/queue_transfer.rs @@ -46,6 +46,6 @@ static QUEUE_WRITE_TEXTURE_OVERFLOW: GpuTestConfiguration = }, ); }, - None, + Some("end up overrunning the bounds of the destination texture"), ); }); diff --git a/tests/tests/ray_tracing/mod.rs b/tests/tests/ray_tracing/mod.rs index e3440034df..c7391a0972 100644 --- a/tests/tests/ray_tracing/mod.rs +++ b/tests/tests/ray_tracing/mod.rs @@ -39,7 +39,7 @@ fn execute(ctx: TestingContext) { }); let blas_geo_size_desc = rt::BlasTriangleGeometrySizeDescriptor { - vertex_format: wgpu::VertexFormat::Float32x4, + vertex_format: wgpu::VertexFormat::Float32x3, vertex_count: vertex_data.len() as u32, index_format: Some(wgpu::IndexFormat::Uint16), index_count: Some(index_data.len() as u32), diff --git a/tests/tests/regression/issue_3349.rs b/tests/tests/regression/issue_3349.rs index 21929bd9b7..b1361722fd 100644 --- a/tests/tests/regression/issue_3349.rs +++ b/tests/tests/regression/issue_3349.rs @@ -163,7 +163,7 @@ async fn multi_stage_data_binding_test(ctx: TestingContext) { }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bg, &[]); + rpass.set_bind_group(0, Some(&bg), &[]); rpass.set_push_constants( wgpu::ShaderStages::VERTEX_FRAGMENT, 0, diff --git a/tests/tests/regression/issue_5553.rs b/tests/tests/regression/issue_5553.rs index 6debb03485..01ffb59d1a 100644 --- a/tests/tests/regression/issue_5553.rs +++ b/tests/tests/regression/issue_5553.rs @@ -24,7 +24,8 @@ static ALLOW_INPUT_NOT_CONSUMED: GpuTestConfiguration = push_constant_ranges: &[], }); - ctx.device + let _ = ctx + .device .create_render_pipeline(&RenderPipelineDescriptor { label: Some("Pipeline"), layout: Some(&pipeline_layout), diff --git a/tests/tests/render_pass_ownership.rs b/tests/tests/render_pass_ownership.rs index 502375e736..5086d38d91 100644 --- a/tests/tests/render_pass_ownership.rs +++ b/tests/tests/render_pass_ownership.rs @@ -9,7 +9,7 @@ //! * rpass.multi_draw_indirect_count //! * rpass.multi_draw_indexed_indirect_count //! -use std::num::NonZeroU64; +use std::{mem::size_of, num::NonZeroU64}; use wgpu::util::DeviceExt as _; use wgpu_test::{gpu_test, valid, GpuTestConfiguration, TestParameters, TestingContext}; @@ -87,7 +87,7 @@ async fn render_pass_resource_ownership(ctx: TestingContext) { drop(depth_stencil_view); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); rpass.begin_occlusion_query(0); @@ -163,7 +163,7 @@ async fn render_pass_query_set_ownership_pipeline_statistics(ctx: TestingContext ..Default::default() }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); rpass.begin_pipeline_statistics_query(&query_set, 0); @@ -242,7 +242,7 @@ async fn render_pass_query_set_ownership_timestamps(ctx: TestingContext) { rpass.write_timestamp(&query_set_write_timestamp, 0); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); rpass.draw(0..3, 0..1); @@ -305,7 +305,7 @@ async fn render_pass_keep_encoder_alive(ctx: TestingContext) { // Record some a draw command. rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); rpass.draw(0..3, 0..1); @@ -367,7 +367,7 @@ fn resource_setup(ctx: &TestingContext) -> ResourceSetup { source: wgpu::ShaderSource::Wgsl(SHADER_SRC.into()), }); - let buffer_size = 4 * std::mem::size_of::() as u64; + let buffer_size = 4 * size_of::() as u64; let bgl = ctx .device @@ -418,7 +418,7 @@ fn resource_setup(ctx: &TestingContext) -> ResourceSetup { let vertex_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { label: Some("vertex_buffer"), usage: wgpu::BufferUsages::VERTEX, - size: std::mem::size_of::() as u64 * vertex_count as u64, + size: size_of::() as u64 * vertex_count as u64, mapped_at_creation: false, }); diff --git a/tests/tests/resource_error.rs b/tests/tests/resource_error.rs index 98b55044a7..d071053ebd 100644 --- a/tests/tests/resource_error.rs +++ b/tests/tests/resource_error.rs @@ -14,15 +14,19 @@ static BAD_BUFFER: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(| mapped_at_creation: false, }) }, - None, + Some("`map` usage can only be combined with the opposite `copy`"), ); fail( &ctx.device, || buffer.slice(..).map_async(wgpu::MapMode::Write, |_| {}), - None, + Some("Buffer with '' label is invalid"), + ); + fail( + &ctx.device, + || buffer.unmap(), + Some("Buffer with '' label is invalid"), ); - fail(&ctx.device, || buffer.unmap(), None); valid(&ctx.device, || buffer.destroy()); valid(&ctx.device, || buffer.destroy()); }); @@ -47,7 +51,7 @@ static BAD_TEXTURE: GpuTestConfiguration = GpuTestConfiguration::new().run_sync( view_formats: &[], }) }, - None, + Some("dimension x is zero"), ); fail( @@ -55,7 +59,7 @@ static BAD_TEXTURE: GpuTestConfiguration = GpuTestConfiguration::new().run_sync( || { let _ = texture.create_view(&wgpu::TextureViewDescriptor::default()); }, - None, + Some("Texture with '' label is invalid"), ); valid(&ctx.device, || texture.destroy()); valid(&ctx.device, || texture.destroy()); diff --git a/tests/tests/shader/mod.rs b/tests/tests/shader/mod.rs index 7d6ed7aaaa..2e7dfd9424 100644 --- a/tests/tests/shader/mod.rs +++ b/tests/tests/shader/mod.rs @@ -349,7 +349,7 @@ async fn shader_input_output_test( timestamp_writes: None, }); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bg, &[]); + cpass.set_bind_group(0, Some(&bg), &[]); if let InputStorageType::PushConstant = storage_type { cpass.set_push_constants(0, bytemuck::cast_slice(&test.input_values)) diff --git a/tests/tests/shader/zero_init_workgroup_mem.rs b/tests/tests/shader/zero_init_workgroup_mem.rs index beacb4fcc8..084498770e 100644 --- a/tests/tests/shader/zero_init_workgroup_mem.rs +++ b/tests/tests/shader/zero_init_workgroup_mem.rs @@ -119,7 +119,7 @@ static ZERO_INIT_WORKGROUP_MEMORY: GpuTestConfiguration = GpuTestConfiguration:: cpass.set_pipeline(&pipeline_read); for i in 0..NR_OF_DISPATCHES { - cpass.set_bind_group(0, &bg, &[i * BUFFER_BINDING_SIZE]); + cpass.set_bind_group(0, Some(&bg), &[i * BUFFER_BINDING_SIZE]); cpass.dispatch_workgroups(DISPATCH_SIZE.0, DISPATCH_SIZE.1, DISPATCH_SIZE.2); } drop(cpass); diff --git a/tests/tests/shader_view_format/mod.rs b/tests/tests/shader_view_format/mod.rs index b2bc0426eb..052573bc0d 100644 --- a/tests/tests/shader_view_format/mod.rs +++ b/tests/tests/shader_view_format/mod.rs @@ -148,7 +148,7 @@ async fn reinterpret( occlusion_query_set: None, }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.draw(0..3, 0..1); drop(rpass); ctx.queue.submit(Some(encoder.finish())); diff --git a/tests/tests/subgroup_operations/mod.rs b/tests/tests/subgroup_operations/mod.rs index 7696fb78df..ecf8adfd7d 100644 --- a/tests/tests/subgroup_operations/mod.rs +++ b/tests/tests/subgroup_operations/mod.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, num::NonZeroU64}; +use std::{borrow::Cow, mem::size_of, num::NonZeroU64}; use wgpu_test::{gpu_test, GpuTestConfiguration, TestParameters}; @@ -35,7 +35,7 @@ static SUBGROUP_OPERATIONS: GpuTestConfiguration = GpuTestConfiguration::new() let storage_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: None, - size: THREAD_COUNT * std::mem::size_of::() as u64, + size: THREAD_COUNT * size_of::() as u64, usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::COPY_SRC, @@ -50,9 +50,7 @@ static SUBGROUP_OPERATIONS: GpuTestConfiguration = GpuTestConfiguration::new() ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Storage { read_only: false }, has_dynamic_offset: false, - min_binding_size: NonZeroU64::new( - THREAD_COUNT * std::mem::size_of::() as u64, - ), + min_binding_size: NonZeroU64::new(THREAD_COUNT * size_of::() as u64), }, count: None, }], @@ -95,7 +93,7 @@ static SUBGROUP_OPERATIONS: GpuTestConfiguration = GpuTestConfiguration::new() timestamp_writes: None, }); cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups(1, 1, 1); } ctx.queue.submit(Some(encoder.finish())); diff --git a/tests/tests/transfer.rs b/tests/tests/transfer.rs index e69f975598..3408fe2e83 100644 --- a/tests/tests/transfer.rs +++ b/tests/tests/transfer.rs @@ -64,6 +64,6 @@ static COPY_OVERFLOW_Z: GpuTestConfiguration = GpuTestConfiguration::new().run_s ); ctx.queue.submit(Some(encoder.finish())); }, - None, + Some("unable to select texture mip level"), ); }); diff --git a/tests/tests/vertex_formats/mod.rs b/tests/tests/vertex_formats/mod.rs index 60ef177efa..d447ac8f7e 100644 --- a/tests/tests/vertex_formats/mod.rs +++ b/tests/tests/vertex_formats/mod.rs @@ -1,6 +1,6 @@ //! Tests that vertex formats pass through to vertex shaders accurately. -use std::num::NonZeroU64; +use std::{mem::size_of_val, num::NonZeroU64}; use wgpu::util::{BufferInitDescriptor, DeviceExt}; @@ -273,7 +273,7 @@ async fn vertex_formats_common(ctx: TestingContext, tests: &[Test<'_>]) { let pipeline = ctx.device.create_render_pipeline(&pipeline_desc); let expected = test.checksums; - let buffer_size = (std::mem::size_of_val(&expected[0]) * expected.len()) as u64; + let buffer_size = (size_of_val(&expected[0]) * expected.len()) as u64; let cpu_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { label: None, size: buffer_size, @@ -315,7 +315,7 @@ async fn vertex_formats_common(ctx: TestingContext, tests: &[Test<'_>]) { rpass.set_vertex_buffer(0, buffer_input.slice(..)); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bg, &[]); + rpass.set_bind_group(0, Some(&bg), &[]); // Draw three vertices and no instance, which is enough to generate the // checksums. diff --git a/tests/tests/vertex_indices/mod.rs b/tests/tests/vertex_indices/mod.rs index 5a847d0fbb..5c5ce8a202 100644 --- a/tests/tests/vertex_indices/mod.rs +++ b/tests/tests/vertex_indices/mod.rs @@ -3,7 +3,7 @@ //! We need tests for these as the backends use various schemes to work around the lack //! of support for things like `gl_BaseInstance` in shaders. -use std::{num::NonZeroU64, ops::Range}; +use std::{mem::size_of_val, num::NonZeroU64, ops::Range}; use itertools::Itertools; use strum::IntoEnumIterator; @@ -341,7 +341,7 @@ async fn vertex_index_common(ctx: TestingContext) { let expected = test.expectation(&ctx); - let buffer_size = (std::mem::size_of_val(&expected[0]) * expected.len()) as u64; + let buffer_size = (size_of_val(&expected[0]) * expected.len()) as u64; let cpu_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { label: None, size: buffer_size, @@ -409,7 +409,7 @@ async fn vertex_index_common(ctx: TestingContext) { render_encoder.set_vertex_buffer(1, identity_buffer.slice(..)); render_encoder.set_index_buffer(identity_buffer.slice(..), wgpu::IndexFormat::Uint32); render_encoder.set_pipeline(pipeline); - render_encoder.set_bind_group(0, &bg, &[]); + render_encoder.set_bind_group(0, Some(&bg), &[]); let draws = test.case.draws(); diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 22d813c4cb..1b9ce98488 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -57,6 +57,9 @@ serde = ["dep:serde", "wgt/serde", "arrayvec/serde"] ## Enable API tracing. trace = ["dep:ron", "serde", "naga/serialize"] +## Enable lock order observation. +observe_locks = ["dep:ron", "serde/serde_derive"] + ## Enable API replaying replay = ["serde", "naga/deserialize"] diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 9fd344c48c..7e5e58e973 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -6,8 +6,8 @@ use crate::{ init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction}, pipeline::{ComputePipeline, RenderPipeline}, resource::{ - Buffer, DestroyedResourceError, Labeled, MissingBufferUsageError, MissingTextureUsageError, - ResourceErrorIdent, Sampler, TextureView, TrackingData, + Buffer, DestroyedResourceError, InvalidResourceError, Labeled, MissingBufferUsageError, + MissingTextureUsageError, ResourceErrorIdent, Sampler, TextureView, TrackingData, }, resource_log, snatch::{SnatchGuard, Snatchable}, @@ -80,16 +80,6 @@ pub enum CreateBindGroupLayoutError { pub enum CreateBindGroupError { #[error(transparent)] Device(#[from] DeviceError), - #[error("Bind group layout is invalid")] - InvalidLayout, - #[error("BufferId {0:?} is invalid")] - InvalidBufferId(BufferId), - #[error("TextureViewId {0:?} is invalid")] - InvalidTextureViewId(TextureViewId), - #[error("SamplerId {0:?} is invalid")] - InvalidSamplerId(SamplerId), - #[error("TlasId {0:?} is invalid or destroyed")] - InvalidTlasId(TlasId), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), #[error( @@ -191,6 +181,8 @@ pub enum CreateBindGroupError { StorageReadNotSupported(wgt::TextureFormat), #[error(transparent)] ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } #[derive(Clone, Debug, Error)] @@ -551,8 +543,6 @@ impl BindGroupLayout { pub enum CreatePipelineLayoutError { #[error(transparent)] Device(#[from] DeviceError), - #[error("BindGroupLayoutId {0:?} is invalid")] - InvalidBindGroupLayoutId(BindGroupLayoutId), #[error( "Push constant at index {index} has range bound {bound} not aligned to {}", wgt::PUSH_CONSTANT_ALIGNMENT @@ -576,6 +566,8 @@ pub enum CreatePipelineLayoutError { TooManyBindings(BindingTypeMaxCountError), #[error("Bind group layout count {actual} exceeds device bind group limit {max}")] TooManyGroups { actual: usize, max: usize }, + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } #[derive(Clone, Debug, Error)] @@ -892,6 +884,16 @@ pub(crate) fn buffer_binding_type_alignment( } } +pub(crate) fn buffer_binding_type_bounds_check_alignment( + alignments: &hal::Alignments, + binding_type: wgt::BufferBindingType, +) -> wgt::BufferAddress { + match binding_type { + wgt::BufferBindingType::Uniform => alignments.uniform_bounds_check_alignment.get(), + wgt::BufferBindingType::Storage { .. } => wgt::COPY_BUFFER_ALIGNMENT, + } +} + #[derive(Debug)] pub struct BindGroup { pub(crate) raw: Snatchable>, @@ -1001,10 +1003,10 @@ crate::impl_trackable!(BindGroup); #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum GetBindGroupLayoutError { - #[error("Pipeline is invalid")] - InvalidPipeline, #[error("Invalid group index {0}")] InvalidGroupIndex(u32), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } #[derive(Clone, Debug, Error, Eq, PartialEq)] diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 56f7d551b0..394858f9fd 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -92,7 +92,10 @@ use crate::{ id, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, pipeline::{PipelineFlags, RenderPipeline, VertexStep}, - resource::{Buffer, DestroyedResourceError, Labeled, ParentDevice, TrackingData}, + resource::{ + Buffer, DestroyedResourceError, Fallible, InvalidResourceError, Labeled, ParentDevice, + TrackingData, + }, resource_log, snatch::SnatchGuard, track::RenderBundleScope, @@ -100,7 +103,7 @@ use crate::{ }; use arrayvec::ArrayVec; -use std::{borrow::Cow, mem, num::NonZeroU32, ops::Range, sync::Arc}; +use std::{borrow::Cow, mem::size_of, num::NonZeroU32, ops::Range, sync::Arc}; use thiserror::Error; use super::{ @@ -578,15 +581,20 @@ impl RenderBundleEncoder { fn set_bind_group( state: &mut State, - bind_group_guard: &crate::lock::RwLockReadGuard>, + bind_group_guard: &crate::storage::Storage>, dynamic_offsets: &[u32], index: u32, num_dynamic_offsets: usize, - bind_group_id: id::Id, + bind_group_id: Option>, ) -> Result<(), RenderBundleErrorInner> { - let bind_group = bind_group_guard - .get_owned(bind_group_id) - .map_err(|_| RenderCommandError::InvalidBindGroupId(bind_group_id))?; + if bind_group_id.is_none() { + // TODO: do appropriate cleanup for null bind_group. + return Ok(()); + } + + let bind_group_id = bind_group_id.unwrap(); + + let bind_group = bind_group_guard.get(bind_group_id).get()?; bind_group.same_device(&state.device)?; @@ -623,15 +631,13 @@ fn set_bind_group( fn set_pipeline( state: &mut State, - pipeline_guard: &crate::lock::RwLockReadGuard>, + pipeline_guard: &crate::storage::Storage>, context: &RenderPassContext, is_depth_read_only: bool, is_stencil_read_only: bool, pipeline_id: id::Id, ) -> Result<(), RenderBundleErrorInner> { - let pipeline = pipeline_guard - .get_owned(pipeline_id) - .map_err(|_| RenderCommandError::InvalidPipelineId(pipeline_id))?; + let pipeline = pipeline_guard.get(pipeline_id).get()?; pipeline.same_device(&state.device)?; @@ -666,15 +672,13 @@ fn set_pipeline( fn set_index_buffer( state: &mut State, - buffer_guard: &crate::lock::RwLockReadGuard>, + buffer_guard: &crate::storage::Storage>, buffer_id: id::Id, index_format: wgt::IndexFormat, offset: u64, size: Option, ) -> Result<(), RenderBundleErrorInner> { - let buffer = buffer_guard - .get_owned(buffer_id) - .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id))?; + let buffer = buffer_guard.get(buffer_id).get()?; state .trackers @@ -701,7 +705,7 @@ fn set_index_buffer( fn set_vertex_buffer( state: &mut State, - buffer_guard: &crate::lock::RwLockReadGuard>, + buffer_guard: &crate::storage::Storage>, slot: u32, buffer_id: id::Id, offset: u64, @@ -716,9 +720,7 @@ fn set_vertex_buffer( .into()); } - let buffer = buffer_guard - .get_owned(buffer_id) - .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id))?; + let buffer = buffer_guard.get(buffer_id).get()?; state .trackers @@ -845,7 +847,7 @@ fn draw_indexed( fn multi_draw_indirect( state: &mut State, dynamic_offsets: &[u32], - buffer_guard: &crate::lock::RwLockReadGuard>, + buffer_guard: &crate::storage::Storage>, buffer_id: id::Id, offset: u64, indexed: bool, @@ -857,9 +859,7 @@ fn multi_draw_indirect( let pipeline = state.pipeline()?; let used_bind_groups = pipeline.used_bind_groups; - let buffer = buffer_guard - .get_owned(buffer_id) - .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id))?; + let buffer = buffer_guard.get(buffer_id).get()?; state .trackers @@ -873,7 +873,7 @@ fn multi_draw_indirect( .buffer_memory_init_actions .extend(buffer.initialization_status.read().create_action( &buffer, - offset..(offset + mem::size_of::() as u64), + offset..(offset + size_of::() as u64), MemoryInitKind::NeedsInitializedMemory, )); @@ -981,12 +981,17 @@ impl RenderBundle { num_dynamic_offsets, bind_group, } => { - let raw_bg = bind_group.try_raw(snatch_guard)?; + let mut bg = None; + if bind_group.is_some() { + let bind_group = bind_group.as_ref().unwrap(); + let raw_bg = bind_group.try_raw(snatch_guard)?; + bg = Some(raw_bg); + } unsafe { raw.set_bind_group( pipeline_layout.as_ref().unwrap().raw(), *index, - raw_bg, + bg, &offsets[..*num_dynamic_offsets], ) }; @@ -1501,7 +1506,7 @@ impl State { let offsets = &contents.dynamic_offsets; return Some(ArcRenderCommand::SetBindGroup { index: i.try_into().unwrap(), - bind_group: contents.bind_group.clone(), + bind_group: Some(contents.bind_group.clone()), num_dynamic_offsets: offsets.end - offsets.start, }); } @@ -1526,6 +1531,8 @@ pub(super) enum RenderBundleErrorInner { MissingDownlevelFlags(#[from] MissingDownlevelFlags), #[error(transparent)] Bind(#[from] BindError), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } impl From for RenderBundleErrorInner @@ -1581,7 +1588,7 @@ pub mod bundle_ffi { pub unsafe extern "C" fn wgpu_render_bundle_set_bind_group( bundle: &mut RenderBundleEncoder, index: u32, - bind_group_id: id::BindGroupId, + bind_group_id: Option, offsets: *const DynamicOffset, offset_length: usize, ) { diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 944dd40af4..3a12a54117 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -11,8 +11,8 @@ use crate::{ id::{BufferId, CommandEncoderId, TextureId}, init_tracker::{MemoryInitKind, TextureInitRange}, resource::{ - DestroyedResourceError, Labeled, MissingBufferUsageError, ParentDevice, ResourceErrorIdent, - Texture, TextureClearMode, + DestroyedResourceError, InvalidResourceError, Labeled, MissingBufferUsageError, + ParentDevice, ResourceErrorIdent, Texture, TextureClearMode, }, snatch::SnatchGuard, track::{TextureSelector, TextureTrackerSetSingle}, @@ -27,10 +27,6 @@ use wgt::{math::align_to, BufferAddress, BufferUsages, ImageSubresourceRange, Te pub enum ClearError { #[error("To use clear_texture the CLEAR_TEXTURE feature needs to be enabled")] MissingClearTextureFeature, - #[error("BufferId {0:?} is invalid")] - InvalidBufferId(BufferId), - #[error("TextureId {0:?} is invalid")] - InvalidTextureId(TextureId), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), #[error("{0} can not be cleared")] @@ -75,6 +71,8 @@ whereas subesource range specified start {subresource_base_array_layer} and coun Device(#[from] DeviceError), #[error(transparent)] CommandEncoderError(#[from] CommandEncoderError), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } impl Global { @@ -90,27 +88,18 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; - - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + .get(command_encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(TraceCommand::ClearBuffer { dst, offset, size }); } - let dst_buffer = hub - .buffers - .get(dst) - .map_err(|_| ClearError::InvalidBufferId(dst))?; + let dst_buffer = hub.buffers.get(dst).get()?; dst_buffer.same_device_as(cmd_buf.as_ref())?; @@ -163,7 +152,7 @@ impl Global { // actual hal barrier & operation let dst_barrier = dst_pending.map(|pending| pending.into_hal(&dst_buffer, &snatch_guard)); - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.transition_buffers(dst_barrier.as_slice()); cmd_buf_raw.clear_buffer(dst_raw, offset..end_offset); @@ -182,17 +171,11 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; - - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + .get(command_encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { @@ -206,10 +189,7 @@ impl Global { return Err(ClearError::MissingClearTextureFeature); } - let dst_texture = hub - .textures - .get(dst) - .map_err(|_| ClearError::InvalidTextureId(dst))?; + let dst_texture = hub.textures.get(dst).get()?; dst_texture.same_device_as(cmd_buf.as_ref())?; @@ -249,7 +229,7 @@ impl Global { let device = &cmd_buf.device; device.check_is_valid()?; - let (encoder, tracker) = cmd_buf_data.open_encoder_and_tracker()?; + let (encoder, tracker) = cmd_buf_data.open_encoder_and_tracker(&cmd_buf.device)?; let snatch_guard = device.snatchable_lock.read(); clear_texture( diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 2c1d62cbb7..fe5f68c12f 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -17,8 +17,8 @@ use crate::{ init_tracker::{BufferInitTrackerAction, MemoryInitKind}, pipeline::ComputePipeline, resource::{ - self, Buffer, DestroyedResourceError, Labeled, MissingBufferUsageError, ParentDevice, - Trackable, + self, Buffer, DestroyedResourceError, InvalidResourceError, Labeled, + MissingBufferUsageError, ParentDevice, Trackable, }, snatch::SnatchGuard, track::{ResourceUsageCompatibilityError, Tracker, TrackerIndex, UsageScope}, @@ -31,7 +31,7 @@ use wgt::{BufferAddress, DynamicOffset}; use super::{bind::BinderError, memory_init::CommandBufferTextureMemoryActions}; use crate::ray_tracing::TlasAction; use std::sync::Arc; -use std::{fmt, mem, str}; +use std::{fmt, mem::size_of, str}; pub struct ComputePass { /// All pass data & records is stored here. @@ -132,14 +132,8 @@ pub enum ComputePassErrorInner { Encoder(#[from] CommandEncoderError), #[error("Parent encoder is invalid")] InvalidParentEncoder, - #[error("BindGroupId {0:?} is invalid")] - InvalidBindGroupId(id::BindGroupId), #[error("Bind group index {index} is greater than the device's requested `max_bind_group` limit {max}")] BindGroupIndexOutOfRange { index: u32, max: u32 }, - #[error("ComputePipelineId {0:?} is invalid")] - InvalidPipelineId(id::ComputePipelineId), - #[error("QuerySet {0:?} is invalid")] - InvalidQuerySet(id::QuerySetId), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), #[error("Indirect buffer uses bytes {offset}..{end_offset} which overruns indirect buffer of size {buffer_size}")] @@ -148,8 +142,6 @@ pub enum ComputePassErrorInner { end_offset: u64, buffer_size: u64, }, - #[error("BufferId {0:?} is invalid")] - InvalidBufferId(id::BufferId), #[error(transparent)] ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError), #[error(transparent)] @@ -176,6 +168,8 @@ pub enum ComputePassErrorInner { MissingDownlevelFlags(#[from] MissingDownlevelFlags), #[error("The compute pass has already been ended and no further commands can be recorded")] PassEnded, + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } /// Error encountered when performing a compute pass. @@ -299,22 +293,21 @@ impl Global { let make_err = |e, arc_desc| (ComputePass::new(None, arc_desc), Some(e)); - let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { - Ok(cmd_buf) => cmd_buf, - Err(_) => return make_err(CommandEncoderError::Invalid, arc_desc), - }; + let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); - match cmd_buf.lock_encoder() { + match cmd_buf + .try_get() + .map_err(|e| e.into()) + .and_then(|mut cmd_buf_data| cmd_buf_data.lock_encoder()) + { Ok(_) => {} Err(e) => return make_err(e, arc_desc), }; arc_desc.timestamp_writes = if let Some(tw) = desc.timestamp_writes { - let Ok(query_set) = hub.query_sets.get(tw.query_set) else { - return make_err( - CommandEncoderError::InvalidTimestampWritesQuerySetId(tw.query_set), - arc_desc, - ); + let query_set = match hub.query_sets.get(tw.query_set).get() { + Ok(query_set) => query_set, + Err(e) => return make_err(e.into(), arc_desc), }; Some(ArcPassTimestampWrites { @@ -329,25 +322,8 @@ impl Global { (ComputePass::new(Some(cmd_buf), arc_desc), None) } - pub fn compute_pass_end(&self, pass: &mut ComputePass) -> Result<(), ComputePassError> { - let scope = PassErrorScope::Pass; - - let cmd_buf = pass - .parent - .as_ref() - .ok_or(ComputePassErrorInner::InvalidParentEncoder) - .map_pass_err(scope)?; - - cmd_buf.unlock_encoder().map_pass_err(scope)?; - - let base = pass - .base - .take() - .ok_or(ComputePassErrorInner::PassEnded) - .map_pass_err(scope)?; - self.compute_pass_end_impl(cmd_buf, base, pass.timestamp_writes.take()) - } - + /// Note that this differs from [`Self::compute_pass_end`], it will + /// create a new pass, replay the commands and end the pass. #[doc(hidden)] #[cfg(any(feature = "serde", feature = "replay"))] pub fn compute_pass_end_with_unresolved_commands( @@ -356,19 +332,16 @@ impl Global { base: BasePass, timestamp_writes: Option<&PassTimestampWrites>, ) -> Result<(), ComputePassError> { - let hub = &self.hub; - let scope = PassErrorScope::Pass; - - let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid).map_pass_err(scope), - }; - cmd_buf.check_recording().map_pass_err(scope)?; + let pass_scope = PassErrorScope::Pass; #[cfg(feature = "trace")] { - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let cmd_buf = self + .hub + .command_buffers + .get(encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get().map_pass_err(pass_scope)?; + if let Some(ref mut list) = cmd_buf_data.commands { list.push(crate::device::trace::Command::RunComputePass { base: BasePass { @@ -383,50 +356,61 @@ impl Global { } } - let commands = - super::ComputeCommand::resolve_compute_command_ids(&self.hub, &base.commands)?; - - let timestamp_writes = if let Some(tw) = timestamp_writes { - Some(ArcPassTimestampWrites { - query_set: hub - .query_sets - .get(tw.query_set) - .map_err(|_| ComputePassErrorInner::InvalidQuerySet(tw.query_set)) - .map_pass_err(scope)?, - beginning_of_pass_write_index: tw.beginning_of_pass_write_index, - end_of_pass_write_index: tw.end_of_pass_write_index, - }) - } else { - None + let BasePass { + label, + commands, + dynamic_offsets, + string_data, + push_constant_data, + } = base; + + let (mut compute_pass, encoder_error) = self.command_encoder_create_compute_pass( + encoder_id, + &ComputePassDescriptor { + label: label.as_deref().map(std::borrow::Cow::Borrowed), + timestamp_writes, + }, + ); + if let Some(err) = encoder_error { + return Err(ComputePassError { + scope: pass_scope, + inner: err.into(), + }); }; - self.compute_pass_end_impl( - &cmd_buf, - BasePass { - label: base.label, - commands, - dynamic_offsets: base.dynamic_offsets, - string_data: base.string_data, - push_constant_data: base.push_constant_data, - }, - timestamp_writes, - ) + compute_pass.base = Some(BasePass { + label, + commands: super::ComputeCommand::resolve_compute_command_ids(&self.hub, &commands)?, + dynamic_offsets, + string_data, + push_constant_data, + }); + + self.compute_pass_end(&mut compute_pass) } - fn compute_pass_end_impl( - &self, - cmd_buf: &CommandBuffer, - base: BasePass, - mut timestamp_writes: Option, - ) -> Result<(), ComputePassError> { + pub fn compute_pass_end(&self, pass: &mut ComputePass) -> Result<(), ComputePassError> { profiling::scope!("CommandEncoder::run_compute_pass"); let pass_scope = PassErrorScope::Pass; + let cmd_buf = pass + .parent + .as_ref() + .ok_or(ComputePassErrorInner::InvalidParentEncoder) + .map_pass_err(pass_scope)?; + + let base = pass + .base + .take() + .ok_or(ComputePassErrorInner::PassEnded) + .map_pass_err(pass_scope)?; + let device = &cmd_buf.device; device.check_is_valid().map_pass_err(pass_scope)?; - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let mut cmd_buf_data = cmd_buf.try_get().map_pass_err(pass_scope)?; + cmd_buf_data.unlock_encoder().map_pass_err(pass_scope)?; + let cmd_buf_data = &mut *cmd_buf_data; let encoder = &mut cmd_buf_data.encoder; let status = &mut cmd_buf_data.status; @@ -434,10 +418,10 @@ impl Global { // We automatically keep extending command buffers over time, and because // we want to insert a command buffer _before_ what we're about to record, // we need to make sure to close the previous one. - encoder.close().map_pass_err(pass_scope)?; + encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?; // will be reset to true if recording is done without errors *status = CommandEncoderStatus::Error; - let raw_encoder = encoder.open().map_pass_err(pass_scope)?; + let raw_encoder = encoder.open(&cmd_buf.device).map_pass_err(pass_scope)?; let mut state = State { binder: Binder::new(), @@ -469,9 +453,9 @@ impl Global { state.tracker.textures.set_size(indices.textures.size()); let timestamp_writes: Option> = - if let Some(tw) = timestamp_writes.take() { + if let Some(tw) = pass.timestamp_writes.take() { tw.query_set - .same_device_as(cmd_buf) + .same_device_as(cmd_buf.as_ref()) .map_pass_err(pass_scope)?; let query_set = state.tracker.query_sets.insert_single(tw.query_set); @@ -505,7 +489,7 @@ impl Global { }; let hal_desc = hal::ComputePassDescriptor { - label: hal_label(base.label.as_deref(), self.instance.flags), + label: hal_label(base.label.as_deref(), device.instance_flags), timestamp_writes, }; @@ -619,12 +603,12 @@ impl Global { } = state; // Stop the current command buffer. - encoder.close().map_pass_err(pass_scope)?; + encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?; // Create a new command buffer, which we will insert _before_ the body of the compute pass. // // Use that buffer to insert barriers and clear discarded images. - let transit = encoder.open().map_pass_err(pass_scope)?; + let transit = encoder.open(&cmd_buf.device).map_pass_err(pass_scope)?; fixup_discarded_surfaces( pending_discard_init_fixups.into_iter(), transit, @@ -639,7 +623,9 @@ impl Global { &snatch_guard, ); // Close the command buffer, and swap it with the previous. - encoder.close_and_swap().map_pass_err(pass_scope)?; + encoder + .close_and_swap(&cmd_buf.device) + .map_pass_err(pass_scope)?; Ok(()) } @@ -651,10 +637,8 @@ fn set_bind_group( dynamic_offsets: &[DynamicOffset], index: u32, num_dynamic_offsets: usize, - bind_group: Arc, + bind_group: Option>, ) -> Result<(), ComputePassErrorInner> { - bind_group.same_device_as(cmd_buf)?; - let max_bind_groups = state.device.limits.max_bind_groups; if index >= max_bind_groups { return Err(ComputePassErrorInner::BindGroupIndexOutOfRange { @@ -670,7 +654,16 @@ fn set_bind_group( ); state.dynamic_offset_count += num_dynamic_offsets; + if bind_group.is_none() { + // TODO: Handle bind_group None. + return Ok(()); + } + + let bind_group = bind_group.unwrap(); let bind_group = state.tracker.bind_groups.insert_single(bind_group); + + bind_group.same_device_as(cmd_buf)?; + bind_group.validate_dynamic_bindings(index, &state.temp_offsets)?; state @@ -713,7 +706,7 @@ fn set_bind_group( state.raw_encoder.set_bind_group( pipeline_layout, index + i as u32, - raw_bg, + Some(raw_bg), &e.dynamic_offsets, ); } @@ -758,7 +751,7 @@ fn set_pipeline( state.raw_encoder.set_bind_group( pipeline.layout.raw(), start_index as u32 + i as u32, - raw_bg, + Some(raw_bg), &e.dynamic_offsets, ); } @@ -867,7 +860,7 @@ fn dispatch_indirect( .merge_single(&buffer, hal::BufferUses::INDIRECT)?; buffer.check_usage(wgt::BufferUsages::INDIRECT)?; - let end_offset = offset + mem::size_of::() as u64; + let end_offset = offset + size_of::() as u64; if end_offset > buffer.size { return Err(ComputePassErrorInner::IndirectBufferOverrun { offset, @@ -965,7 +958,7 @@ impl Global { &self, pass: &mut ComputePass, index: u32, - bind_group_id: id::BindGroupId, + bind_group_id: Option, offsets: &[DynamicOffset], ) -> Result<(), ComputePassError> { let scope = PassErrorScope::SetBindGroup; @@ -986,12 +979,18 @@ impl Global { return Ok(()); } - let hub = &self.hub; - let bind_group = hub - .bind_groups - .get(bind_group_id) - .map_err(|_| ComputePassErrorInner::InvalidBindGroupId(bind_group_id)) - .map_pass_err(scope)?; + let mut bind_group = None; + if bind_group_id.is_some() { + let bind_group_id = bind_group_id.unwrap(); + + let hub = &self.hub; + let bg = hub + .bind_groups + .get(bind_group_id) + .get() + .map_pass_err(scope)?; + bind_group = Some(bg); + } base.commands.push(ArcComputeCommand::SetBindGroup { index, @@ -1021,7 +1020,7 @@ impl Global { let pipeline = hub .compute_pipelines .get(pipeline_id) - .map_err(|_| ComputePassErrorInner::InvalidPipelineId(pipeline_id)) + .get() .map_pass_err(scope)?; base.commands.push(ArcComputeCommand::SetPipeline(pipeline)); @@ -1092,11 +1091,7 @@ impl Global { let scope = PassErrorScope::Dispatch { indirect: true }; let base = pass.base_mut(scope)?; - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| ComputePassErrorInner::InvalidBufferId(buffer_id)) - .map_pass_err(scope)?; + let buffer = hub.buffers.get(buffer_id).get().map_pass_err(scope)?; base.commands .push(ArcComputeCommand::DispatchIndirect { buffer, offset }); @@ -1163,11 +1158,7 @@ impl Global { let base = pass.base_mut(scope)?; let hub = &self.hub; - let query_set = hub - .query_sets - .get(query_set_id) - .map_err(|_| ComputePassErrorInner::InvalidQuerySet(query_set_id)) - .map_pass_err(scope)?; + let query_set = hub.query_sets.get(query_set_id).get().map_pass_err(scope)?; base.commands.push(ArcComputeCommand::WriteTimestamp { query_set, @@ -1187,11 +1178,7 @@ impl Global { let base = pass.base_mut(scope)?; let hub = &self.hub; - let query_set = hub - .query_sets - .get(query_set_id) - .map_err(|_| ComputePassErrorInner::InvalidQuerySet(query_set_id)) - .map_pass_err(scope)?; + let query_set = hub.query_sets.get(query_set_id).get().map_pass_err(scope)?; base.commands .push(ArcComputeCommand::BeginPipelineStatisticsQuery { diff --git a/wgpu-core/src/command/compute_command.rs b/wgpu-core/src/command/compute_command.rs index e16487b7ea..67c23d9452 100644 --- a/wgpu-core/src/command/compute_command.rs +++ b/wgpu-core/src/command/compute_command.rs @@ -13,7 +13,7 @@ pub enum ComputeCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group_id: id::BindGroupId, + bind_group_id: Option, }, SetPipeline(id::ComputePipelineId), @@ -74,7 +74,7 @@ impl ComputeCommand { hub: &crate::hub::Hub, commands: &[ComputeCommand], ) -> Result, super::ComputePassError> { - use super::{ComputePassError, ComputePassErrorInner, PassErrorScope}; + use super::{ComputePassError, PassErrorScope}; let buffers_guard = hub.buffers.read(); let bind_group_guard = hub.bind_groups.read(); @@ -89,23 +89,36 @@ impl ComputeCommand { index, num_dynamic_offsets, bind_group_id, - } => ArcComputeCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group: bind_group_guard.get_owned(bind_group_id).map_err(|_| { + } => { + if bind_group_id.is_none() { + return Ok(ArcComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: None, + }); + } + + let bind_group_id = bind_group_id.unwrap(); + let bg = bind_group_guard.get(bind_group_id).get().map_err(|e| { ComputePassError { scope: PassErrorScope::SetBindGroup, - inner: ComputePassErrorInner::InvalidBindGroupId(bind_group_id), + inner: e.into(), } - })?, - }, + })?; + ArcComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: Some(bg), + } + } ComputeCommand::SetPipeline(pipeline_id) => ArcComputeCommand::SetPipeline( pipelines_guard - .get_owned(pipeline_id) - .map_err(|_| ComputePassError { + .get(pipeline_id) + .get() + .map_err(|e| ComputePassError { scope: PassErrorScope::SetPipelineCompute, - inner: ComputePassErrorInner::InvalidPipelineId(pipeline_id), + inner: e.into(), })?, ), @@ -123,10 +136,10 @@ impl ComputeCommand { ComputeCommand::DispatchIndirect { buffer_id, offset } => { ArcComputeCommand::DispatchIndirect { - buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { + buffer: buffers_guard.get(buffer_id).get().map_err(|e| { ComputePassError { scope: PassErrorScope::Dispatch { indirect: true }, - inner: ComputePassErrorInner::InvalidBufferId(buffer_id), + inner: e.into(), } })?, offset, @@ -147,10 +160,10 @@ impl ComputeCommand { query_set_id, query_index, } => ArcComputeCommand::WriteTimestamp { - query_set: query_set_guard.get_owned(query_set_id).map_err(|_| { + query_set: query_set_guard.get(query_set_id).get().map_err(|e| { ComputePassError { scope: PassErrorScope::WriteTimestamp, - inner: ComputePassErrorInner::InvalidQuerySet(query_set_id), + inner: e.into(), } })?, query_index, @@ -160,10 +173,10 @@ impl ComputeCommand { query_set_id, query_index, } => ArcComputeCommand::BeginPipelineStatisticsQuery { - query_set: query_set_guard.get_owned(query_set_id).map_err(|_| { + query_set: query_set_guard.get(query_set_id).get().map_err(|e| { ComputePassError { scope: PassErrorScope::BeginPipelineStatisticsQuery, - inner: ComputePassErrorInner::InvalidQuerySet(query_set_id), + inner: e.into(), } })?, query_index, @@ -185,7 +198,7 @@ pub enum ArcComputeCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group: Arc, + bind_group: Option>, }, SetPipeline(Arc), @@ -215,6 +228,7 @@ pub enum ArcComputeCommand { }, PushDebugGroup { + #[cfg_attr(target_os = "emscripten", allow(dead_code))] color: u32, len: usize, }, @@ -222,6 +236,7 @@ pub enum ArcComputeCommand { PopDebugGroup, InsertDebugMarker { + #[cfg_attr(target_os = "emscripten", allow(dead_code))] color: u32, len: usize, }, diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index e8578bba05..dd54b60f26 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -1,6 +1,5 @@ use crate::{ binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError}, - id, resource::{ DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError, ResourceErrorIdent, @@ -68,22 +67,12 @@ pub enum DrawError { #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum RenderCommandError { - #[error("BufferId {0:?} is invalid")] - InvalidBufferId(id::BufferId), - #[error("BindGroupId {0:?} is invalid")] - InvalidBindGroupId(id::BindGroupId), - #[error("Render bundle {0:?} is invalid")] - InvalidRenderBundle(id::RenderBundleId), #[error("Bind group index {index} is greater than the device's requested `max_bind_group` limit {max}")] BindGroupIndexOutOfRange { index: u32, max: u32 }, #[error("Vertex buffer index {index} is greater than the device's requested `max_vertex_buffers` limit {max}")] VertexBufferIndexOutOfRange { index: u32, max: u32 }, #[error("Dynamic buffer offset {0} does not respect device's requested `{1}` limit {2}")] UnalignedBufferOffset(u64, &'static str, u32), - #[error("RenderPipelineId {0:?} is invalid")] - InvalidPipelineId(id::RenderPipelineId), - #[error("QuerySet {0:?} is invalid")] - InvalidQuerySet(id::QuerySetId), #[error("Render pipeline targets are incompatible with render pass")] IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError), #[error("{0} writes to depth, while the pass has read-only depth access")] diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index d31a41bd8a..d2ba83a64b 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -33,7 +33,7 @@ use crate::snatch::SnatchGuard; use crate::init_tracker::BufferInitTrackerAction; use crate::ray_tracing::{BlasAction, TlasAction}; -use crate::resource::Labeled; +use crate::resource::{InvalidResourceError, Labeled}; use crate::track::{DeviceTracker, Tracker, UsageScope}; use crate::LabelHelpers; use crate::{api_log, global::Global, id, resource_log, Label}; @@ -84,8 +84,8 @@ pub(crate) enum CommandEncoderStatus { /// /// When a `CommandEncoder` is left in this state, we have also /// returned an error result from the function that encountered - /// the problem. Future attempts to use the encoder (that is, - /// calls to [`CommandBuffer::get_encoder`]) will also return + /// the problem. Future attempts to use the encoder (for example, + /// calls to [`CommandBufferMutable::check_recording`]) will also return /// errors. /// /// Calling [`Global::command_encoder_finish`] in this state @@ -174,10 +174,10 @@ impl CommandEncoder { /// [l]: CommandEncoder::list /// [`transition_buffers`]: hal::CommandEncoder::transition_buffers /// [`transition_textures`]: hal::CommandEncoder::transition_textures - fn close_and_swap(&mut self) -> Result<(), DeviceError> { + fn close_and_swap(&mut self, device: &Device) -> Result<(), DeviceError> { if self.is_open { self.is_open = false; - let new = unsafe { self.raw.end_encoding()? }; + let new = unsafe { self.raw.end_encoding() }.map_err(|e| device.handle_hal_error(e))?; self.list.insert(self.list.len() - 1, new); } @@ -194,10 +194,11 @@ impl CommandEncoder { /// On return, the underlying hal encoder is closed. /// /// [l]: CommandEncoder::list - fn close(&mut self) -> Result<(), DeviceError> { + fn close(&mut self, device: &Device) -> Result<(), DeviceError> { if self.is_open { self.is_open = false; - let cmd_buf = unsafe { self.raw.end_encoding()? }; + let cmd_buf = + unsafe { self.raw.end_encoding() }.map_err(|e| device.handle_hal_error(e))?; self.list.push(cmd_buf); } @@ -217,11 +218,15 @@ impl CommandEncoder { /// Begin recording a new command buffer, if we haven't already. /// /// The underlying hal encoder is put in the "recording" state. - pub(crate) fn open(&mut self) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> { + pub(crate) fn open( + &mut self, + device: &Device, + ) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> { if !self.is_open { self.is_open = true; let hal_label = self.hal_label.as_deref(); - unsafe { self.raw.begin_encoding(hal_label)? }; + unsafe { self.raw.begin_encoding(hal_label) } + .map_err(|e| device.handle_hal_error(e))?; } Ok(self.raw.as_mut()) @@ -231,9 +236,9 @@ impl CommandEncoder { /// its own label. /// /// The underlying hal encoder is put in the "recording" state. - fn open_pass(&mut self, hal_label: Option<&str>) -> Result<(), DeviceError> { + fn open_pass(&mut self, hal_label: Option<&str>, device: &Device) -> Result<(), DeviceError> { self.is_open = true; - unsafe { self.raw.begin_encoding(hal_label)? }; + unsafe { self.raw.begin_encoding(hal_label) }.map_err(|e| device.handle_hal_error(e))?; Ok(()) } @@ -282,12 +287,115 @@ pub struct CommandBufferMutable { impl CommandBufferMutable { pub(crate) fn open_encoder_and_tracker( &mut self, + device: &Device, ) -> Result<(&mut dyn hal::DynCommandEncoder, &mut Tracker), DeviceError> { - let encoder = self.encoder.open()?; + let encoder = self.encoder.open(device)?; let tracker = &mut self.trackers; Ok((encoder, tracker)) } + + fn lock_encoder_impl(&mut self, lock: bool) -> Result<(), CommandEncoderError> { + match self.status { + CommandEncoderStatus::Recording => { + if lock { + self.status = CommandEncoderStatus::Locked; + } + Ok(()) + } + CommandEncoderStatus::Locked => { + // Any operation on a locked encoder is required to put it into the invalid/error state. + // See https://www.w3.org/TR/webgpu/#encoder-state-locked + self.encoder.discard(); + self.status = CommandEncoderStatus::Error; + Err(CommandEncoderError::Locked) + } + CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording), + CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid), + } + } + + /// Checks that the encoder is in the [`CommandEncoderStatus::Recording`] state. + fn check_recording(&mut self) -> Result<(), CommandEncoderError> { + self.lock_encoder_impl(false) + } + + /// Locks the encoder by putting it in the [`CommandEncoderStatus::Locked`] state. + /// + /// Call [`CommandBufferMutable::unlock_encoder`] to put the [`CommandBuffer`] back into the [`CommandEncoderStatus::Recording`] state. + fn lock_encoder(&mut self) -> Result<(), CommandEncoderError> { + self.lock_encoder_impl(true) + } + + /// Unlocks the [`CommandBuffer`] and puts it back into the [`CommandEncoderStatus::Recording`] state. + /// + /// This function is the counterpart to [`CommandBufferMutable::lock_encoder`]. + /// It is only valid to call this function if the encoder is in the [`CommandEncoderStatus::Locked`] state. + fn unlock_encoder(&mut self) -> Result<(), CommandEncoderError> { + match self.status { + CommandEncoderStatus::Recording => Err(CommandEncoderError::Invalid), + CommandEncoderStatus::Locked => { + self.status = CommandEncoderStatus::Recording; + Ok(()) + } + CommandEncoderStatus::Finished => Err(CommandEncoderError::Invalid), + CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid), + } + } + + pub fn check_finished(&self) -> Result<(), CommandEncoderError> { + match self.status { + CommandEncoderStatus::Finished => Ok(()), + _ => Err(CommandEncoderError::Invalid), + } + } + + pub(crate) fn finish(&mut self, device: &Device) -> Result<(), CommandEncoderError> { + match self.status { + CommandEncoderStatus::Recording => { + if let Err(e) = self.encoder.close(device) { + Err(e.into()) + } else { + self.status = CommandEncoderStatus::Finished; + // Note: if we want to stop tracking the swapchain texture view, + // this is the place to do it. + Ok(()) + } + } + CommandEncoderStatus::Locked => { + self.encoder.discard(); + self.status = CommandEncoderStatus::Error; + Err(CommandEncoderError::Locked) + } + CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording), + CommandEncoderStatus::Error => { + self.encoder.discard(); + Err(CommandEncoderError::Invalid) + } + } + } + + pub(crate) fn into_baked_commands(self) -> BakedCommands { + BakedCommands { + encoder: self.encoder.raw, + list: self.encoder.list, + trackers: self.trackers, + buffer_memory_init_actions: self.buffer_memory_init_actions, + texture_memory_actions: self.texture_memory_actions, + blas_actions: self.blas_actions, + tlas_actions: self.tlas_actions, + } + } + + pub(crate) fn destroy(mut self, device: &Device) { + self.encoder.discard(); + unsafe { + self.encoder.raw.reset_all(self.encoder.list); + } + unsafe { + device.raw().destroy_command_encoder(self.encoder.raw); + } + } } /// A buffer of commands to be submitted to the GPU for execution. @@ -319,22 +427,15 @@ pub struct CommandBuffer { /// This `Option` is populated when the command buffer is first created. /// When this is submitted, dropped, or destroyed, its contents are /// extracted into a [`BakedCommands`] by - /// [`CommandBuffer::extract_baked_commands`]. + /// [`CommandBufferMutable::into_baked_commands`]. pub(crate) data: Mutex>, } impl Drop for CommandBuffer { fn drop(&mut self) { resource_log!("Drop {}", self.error_ident()); - if self.data.lock().is_none() { - return; - } - let mut baked = self.extract_baked_commands(); - unsafe { - baked.encoder.reset_all(baked.list); - } - unsafe { - self.device.raw().destroy_command_encoder(baked.encoder); + if let Some(data) = self.data.lock().take() { + data.destroy(&self.device); } } } @@ -376,6 +477,15 @@ impl CommandBuffer { } } + pub(crate) fn new_invalid(device: &Arc, label: &Label) -> Self { + CommandBuffer { + device: device.clone(), + support_clear_texture: device.features.contains(wgt::Features::CLEAR_TEXTURE), + label: label.to_string(), + data: Mutex::new(rank::COMMAND_BUFFER_DATA, None), + } + } + pub(crate) fn insert_barriers_from_tracker( raw: &mut dyn hal::DynCommandEncoder, base: &mut Tracker, @@ -454,82 +564,19 @@ impl CommandBuffer { } impl CommandBuffer { - fn lock_encoder_impl(&self, lock: bool) -> Result<(), CommandEncoderError> { - let mut cmd_buf_data_guard = self.data.lock(); - let cmd_buf_data = cmd_buf_data_guard.as_mut().unwrap(); - match cmd_buf_data.status { - CommandEncoderStatus::Recording => { - if lock { - cmd_buf_data.status = CommandEncoderStatus::Locked; - } - Ok(()) - } - CommandEncoderStatus::Locked => { - // Any operation on a locked encoder is required to put it into the invalid/error state. - // See https://www.w3.org/TR/webgpu/#encoder-state-locked - cmd_buf_data.encoder.discard(); - cmd_buf_data.status = CommandEncoderStatus::Error; - Err(CommandEncoderError::Locked) - } - CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording), - CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid), - } + pub fn try_get<'a>( + &'a self, + ) -> Result, InvalidResourceError> { + let g = self.data.lock(); + crate::lock::MutexGuard::try_map(g, |data| data.as_mut()) + .map_err(|_| InvalidResourceError(self.error_ident())) } - /// Checks that the encoder is in the [`CommandEncoderStatus::Recording`] state. - fn check_recording(&self) -> Result<(), CommandEncoderError> { - self.lock_encoder_impl(false) - } - - /// Locks the encoder by putting it in the [`CommandEncoderStatus::Locked`] state. - /// - /// Call [`CommandBuffer::unlock_encoder`] to put the [`CommandBuffer`] back into the [`CommandEncoderStatus::Recording`] state. - fn lock_encoder(&self) -> Result<(), CommandEncoderError> { - self.lock_encoder_impl(true) - } - - /// Unlocks the [`CommandBuffer`] and puts it back into the [`CommandEncoderStatus::Recording`] state. - /// - /// This function is the counterpart to [`CommandBuffer::lock_encoder`]. - /// It is only valid to call this function if the encoder is in the [`CommandEncoderStatus::Locked`] state. - fn unlock_encoder(&self) -> Result<(), CommandEncoderError> { - let mut data_lock = self.data.lock(); - let status = &mut data_lock.as_mut().unwrap().status; - match *status { - CommandEncoderStatus::Recording => Err(CommandEncoderError::Invalid), - CommandEncoderStatus::Locked => { - *status = CommandEncoderStatus::Recording; - Ok(()) - } - CommandEncoderStatus::Finished => Err(CommandEncoderError::Invalid), - CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid), - } - } - - pub fn is_finished(&self) -> bool { - match self.data.lock().as_ref().unwrap().status { - CommandEncoderStatus::Finished => true, - _ => false, - } - } - - pub(crate) fn extract_baked_commands(&mut self) -> BakedCommands { - let data = self.data.lock().take().unwrap(); - BakedCommands { - encoder: data.encoder.raw, - list: data.encoder.list, - trackers: data.trackers, - buffer_memory_init_actions: data.buffer_memory_init_actions, - texture_memory_actions: data.texture_memory_actions, - blas_actions: data.blas_actions, - tlas_actions: data.tlas_actions, - } - } - - pub(crate) fn from_arc_into_baked(self: Arc) -> BakedCommands { - let mut command_buffer = Arc::into_inner(self) - .expect("CommandBuffer cannot be destroyed because is still in use"); - command_buffer.extract_baked_commands() + pub fn try_take<'a>(&'a self) -> Result { + self.data + .lock() + .take() + .ok_or_else(|| InvalidResourceError(self.error_ident())) } } @@ -601,18 +648,10 @@ pub enum CommandEncoderError { #[error("Command encoder is locked by a previously created render/compute pass. Before recording any new commands, the pass must be ended.")] Locked, - #[error("QuerySet {0:?} for pass timestamp writes is invalid.")] - InvalidTimestampWritesQuerySetId(id::QuerySetId), - #[error("Attachment TextureViewId {0:?} is invalid")] - InvalidAttachmentId(id::TextureViewId), #[error(transparent)] InvalidColorAttachment(#[from] ColorAttachmentError), - #[error("Resolve attachment TextureViewId {0:?} is invalid")] - InvalidResolveTargetId(id::TextureViewId), - #[error("Depth stencil attachment TextureViewId {0:?} is invalid")] - InvalidDepthStencilAttachmentId(id::TextureViewId), - #[error("Occlusion QuerySetId {0:?} is invalid")] - InvalidOcclusionQuerySetId(id::QuerySetId), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } impl Global { @@ -625,34 +664,15 @@ impl Global { let hub = &self.hub; - let error = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { - Ok(cmd_buf) => { - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); - match cmd_buf_data.status { - CommandEncoderStatus::Recording => { - if let Err(e) = cmd_buf_data.encoder.close() { - Some(e.into()) - } else { - cmd_buf_data.status = CommandEncoderStatus::Finished; - //Note: if we want to stop tracking the swapchain texture view, - // this is the place to do it. - None - } - } - CommandEncoderStatus::Locked => { - cmd_buf_data.encoder.discard(); - cmd_buf_data.status = CommandEncoderStatus::Error; - Some(CommandEncoderError::Locked) - } - CommandEncoderStatus::Finished => Some(CommandEncoderError::NotRecording), - CommandEncoderStatus::Error => { - cmd_buf_data.encoder.discard(); - Some(CommandEncoderError::Invalid) - } - } - } - Err(_) => Some(CommandEncoderError::Invalid), + let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); + + let error = match cmd_buf + .try_get() + .map_err(|e| e.into()) + .and_then(|mut cmd_buf_data| cmd_buf_data.finish(&cmd_buf.device)) + { + Ok(_) => None, + Err(e) => Some(e), }; (encoder_id.into_command_buffer_id(), error) @@ -668,23 +688,19 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid), - }; - cmd_buf.check_recording()?; + let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(TraceCommand::PushDebugGroup(label.to_string())); } - let cmd_buf_raw = cmd_buf_data.encoder.open()?; - if !self - .instance - .flags + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; + if !cmd_buf + .device + .instance_flags .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS) { unsafe { @@ -704,26 +720,21 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid), - }; - cmd_buf.check_recording()?; - - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(TraceCommand::InsertDebugMarker(label.to_string())); } - if !self - .instance - .flags + if !cmd_buf + .device + .instance_flags .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS) { - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.insert_debug_marker(label); } @@ -740,24 +751,19 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid), - }; - cmd_buf.check_recording()?; - - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(TraceCommand::PopDebugGroup); } - let cmd_buf_raw = cmd_buf_data.encoder.open()?; - if !self - .instance - .flags + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; + if !cmd_buf + .device + .instance_flags .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS) { unsafe { @@ -815,7 +821,7 @@ impl Default for StateChange { #[derive(Debug)] struct BindGroupStateChange { - last_states: [StateChange; hal::MAX_BIND_GROUPS], + last_states: [StateChange>; hal::MAX_BIND_GROUPS], } impl BindGroupStateChange { @@ -827,7 +833,7 @@ impl BindGroupStateChange { fn set_and_check_redundant( &mut self, - bind_group_id: id::BindGroupId, + bind_group_id: Option, index: u32, dynamic_offsets: &mut Vec, offsets: &[wgt::DynamicOffset], diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index de5103ac88..d783721fb4 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -7,7 +7,8 @@ use crate::{ id, init_tracker::MemoryInitKind, resource::{ - DestroyedResourceError, MissingBufferUsageError, ParentDevice, QuerySet, Trackable, + DestroyedResourceError, InvalidResourceError, MissingBufferUsageError, ParentDevice, + QuerySet, Trackable, }, track::{StatelessTracker, TrackerIndex}, FastHashMap, @@ -100,12 +101,10 @@ pub enum QueryError { Use(#[from] QueryUseError), #[error("Error encountered while trying to resolve a query")] Resolve(#[from] ResolveError), - #[error("BufferId {0:?} is invalid")] - InvalidBufferId(id::BufferId), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), - #[error("QuerySetId {0:?} is invalid or destroyed")] - InvalidQuerySetId(id::QuerySetId), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } /// Error encountered while trying to use queries @@ -319,22 +318,16 @@ impl Global { ) -> Result<(), QueryError> { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; + .get(command_encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; cmd_buf .device .require_features(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS)?; - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); - #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(TraceCommand::WriteTimestamp { @@ -343,20 +336,14 @@ impl Global { }); } - let encoder = &mut cmd_buf_data.encoder; - let tracker = &mut cmd_buf_data.trackers; - - let raw_encoder = encoder.open()?; + let raw_encoder = cmd_buf_data.encoder.open(&cmd_buf.device)?; - let query_set = hub - .query_sets - .get(query_set_id) - .map_err(|_| QueryError::InvalidQuerySetId(query_set_id))?; - - let query_set = tracker.query_sets.insert_single(query_set); + let query_set = hub.query_sets.get(query_set_id).get()?; query_set.validate_and_write_timestamp(raw_encoder, query_index, None)?; + cmd_buf_data.trackers.query_sets.insert_single(query_set); + Ok(()) } @@ -371,17 +358,11 @@ impl Global { ) -> Result<(), QueryError> { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; - - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + .get(command_encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { @@ -394,32 +375,20 @@ impl Global { }); } - let encoder = &mut cmd_buf_data.encoder; - let tracker = &mut cmd_buf_data.trackers; - let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions; - let raw_encoder = encoder.open()?; - if destination_offset % wgt::QUERY_RESOLVE_BUFFER_ALIGNMENT != 0 { return Err(QueryError::Resolve(ResolveError::BufferOffsetAlignment)); } - let query_set = hub - .query_sets - .get(query_set_id) - .map_err(|_| QueryError::InvalidQuerySetId(query_set_id))?; - - let query_set = tracker.query_sets.insert_single(query_set); + let query_set = hub.query_sets.get(query_set_id).get()?; query_set.same_device_as(cmd_buf.as_ref())?; - let dst_buffer = hub - .buffers - .get(destination) - .map_err(|_| QueryError::InvalidBufferId(destination))?; + let dst_buffer = hub.buffers.get(destination).get()?; dst_buffer.same_device_as(cmd_buf.as_ref())?; - let dst_pending = tracker + let dst_pending = cmd_buf_data + .trackers .buffers .set_single(&dst_buffer, hal::BufferUses::COPY_DST); @@ -465,14 +434,16 @@ impl Global { } // TODO(https://github.com/gfx-rs/wgpu/issues/3993): Need to track initialization state. - buffer_memory_init_actions.extend(dst_buffer.initialization_status.read().create_action( - &dst_buffer, - buffer_start_offset..buffer_end_offset, - MemoryInitKind::ImplicitlyInitialized, - )); + cmd_buf_data.buffer_memory_init_actions.extend( + dst_buffer.initialization_status.read().create_action( + &dst_buffer, + buffer_start_offset..buffer_end_offset, + MemoryInitKind::ImplicitlyInitialized, + ), + ); let raw_dst_buffer = dst_buffer.try_raw(&snatch_guard)?; - + let raw_encoder = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { raw_encoder.transition_buffers(dst_barrier.as_slice()); raw_encoder.copy_query_results( @@ -484,6 +455,8 @@ impl Global { ); } + cmd_buf_data.trackers.query_sets.insert_single(query_set); + Ok(()) } } diff --git a/wgpu-core/src/command/ray_tracing.rs b/wgpu-core/src/command/ray_tracing.rs index 038ff0ece2..b928d6093a 100644 --- a/wgpu-core/src/command/ray_tracing.rs +++ b/wgpu-core/src/command/ray_tracing.rs @@ -15,10 +15,10 @@ use crate::{ use wgt::{math::align_to, BufferAddress, BufferUsages}; -use super::{BakedCommands, CommandBufferMutable, CommandEncoderError}; +use super::{BakedCommands, CommandBufferMutable}; use crate::ray_tracing::BlasTriangleGeometry; use crate::resource::{ - AccelerationStructure, Buffer, Labeled, ScratchBuffer, StagingBuffer, Trackable, + AccelerationStructure, Buffer, Fallible, Labeled, ScratchBuffer, StagingBuffer, Trackable, }; use crate::snatch::SnatchGuard; use crate::storage::Storage; @@ -57,14 +57,9 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; + .get(command_encoder_id.into_command_buffer_id()); let buffer_guard = hub.buffers.read(); let blas_guard = hub.blas_s.read(); @@ -181,7 +176,7 @@ impl Global { let mut scratch_buffer_tlas_size = 0; let mut tlas_storage = Vec::<( - &Tlas, + Arc, hal::AccelerationStructureEntries, u64, )>::new(); @@ -192,14 +187,14 @@ impl Global { )>::new(); for entry in tlas_iter { - let instance_buffer = match buffer_guard.get(entry.instance_buffer_id) { + let instance_buffer = match buffer_guard.get(entry.instance_buffer_id).get() { Ok(buffer) => buffer, Err(_) => { return Err(BuildAccelerationStructureError::InvalidBufferId); } }; let data = cmd_buf_data.trackers.buffers.set_single( - instance_buffer, + &instance_buffer, BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, ); tlas_buf_storage.push((instance_buffer.clone(), data, entry.clone())); @@ -228,6 +223,7 @@ impl Global { let tlas = tlas_guard .get(entry.tlas_id) + .get() .map_err(|_| BuildAccelerationStructureError::InvalidTlasId)?; cmd_buf_data.trackers.tlas_s.set_single(tlas.clone()); @@ -275,28 +271,27 @@ impl Global { .iter() .map(|storage| map_blas(storage, scratch_buffer.raw())); - let tlas_descriptors = - tlas_storage - .iter() - .map(|&(tlas, ref entries, ref scratch_buffer_offset)| { - if tlas.update_mode == wgt::AccelerationStructureUpdateMode::PreferUpdate { - log::info!("only rebuild implemented") - } - hal::BuildAccelerationStructureDescriptor { - entries, - mode: hal::AccelerationStructureBuildMode::Build, - flags: tlas.flags, - source_acceleration_structure: None, - destination_acceleration_structure: tlas.raw(), - scratch_buffer: scratch_buffer.raw(), - scratch_buffer_offset: *scratch_buffer_offset, - } - }); + let tlas_descriptors = tlas_storage + .iter() + .map(|(tlas, entries, scratch_buffer_offset)| { + if tlas.update_mode == wgt::AccelerationStructureUpdateMode::PreferUpdate { + log::info!("only rebuild implemented") + } + hal::BuildAccelerationStructureDescriptor { + entries, + mode: hal::AccelerationStructureBuildMode::Build, + flags: tlas.flags, + source_acceleration_structure: None, + destination_acceleration_structure: tlas.raw(), + scratch_buffer: scratch_buffer.raw(), + scratch_buffer_offset: *scratch_buffer_offset, + } + }); let blas_present = !blas_storage.is_empty(); let tlas_present = !tlas_storage.is_empty(); - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(device)?; build_blas( cmd_buf_raw, @@ -338,14 +333,9 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; + .get(command_encoder_id.into_command_buffer_id()); let buffer_guard = hub.buffers.read(); let blas_guard = hub.blas_s.read(); @@ -490,16 +480,16 @@ impl Global { &mut scratch_buffer_blas_size, &mut blas_storage, )?; - let mut tlas_lock_store = - Vec::<(&dyn hal::DynBuffer, Option, Arc)>::new(); + let mut tlas_lock_store = Vec::<(Option, Arc)>::new(); for package in tlas_iter { let tlas = tlas_guard .get(package.tlas_id) + .get() .map_err(|_| BuildAccelerationStructureError::InvalidTlasId)?; cmd_buf_data.trackers.tlas_s.set_single(tlas.clone()); - tlas_lock_store.push((tlas.instance_buffer.as_ref(), Some(package), tlas.clone())) + tlas_lock_store.push((Some(package), tlas.clone())) } let mut scratch_buffer_tlas_size = 0; @@ -511,9 +501,8 @@ impl Global { )>::new(); let mut instance_buffer_staging_source = Vec::::new(); - for entry in &mut tlas_lock_store { - let package = entry.1.take().unwrap(); - let tlas = &entry.2; + for (package, tlas) in &mut tlas_lock_store { + let package = package.take().unwrap(); let scratch_buffer_offset = scratch_buffer_tlas_size; scratch_buffer_tlas_size += align_to( @@ -534,6 +523,7 @@ impl Global { } let blas = blas_guard .get(instance.blas_id) + .get() .map_err(|_| BuildAccelerationStructureError::InvalidBlasIdForInstance)? .clone(); @@ -574,7 +564,7 @@ impl Global { tlas_storage.push(( tlas, hal::AccelerationStructureEntries::Instances(hal::AccelerationStructureInstances { - buffer: Some(entry.0), + buffer: Some(tlas.instance_buffer.as_ref()), offset: 0, count: instance_count, }), @@ -623,7 +613,7 @@ impl Global { let blas_present = !blas_storage.is_empty(); let tlas_present = !tlas_storage.is_empty(); - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(device)?; build_blas( cmd_buf_raw, @@ -789,13 +779,14 @@ fn iter_blas<'a>( blas_iter: impl Iterator>, cmd_buf_data: &mut CommandBufferMutable, build_command_index: NonZeroU64, - buffer_guard: &RwLockReadGuard>, - blas_guard: &RwLockReadGuard>, + buffer_guard: &RwLockReadGuard>>, + blas_guard: &RwLockReadGuard>>, buf_storage: &mut BufferStorage<'a>, ) -> Result<(), BuildAccelerationStructureError> { for entry in blas_iter { let blas = blas_guard .get(entry.blas_id) + .get() .map_err(|_| BuildAccelerationStructureError::InvalidBlasId)?; cmd_buf_data.trackers.blas_s.set_single(blas.clone()); @@ -837,16 +828,16 @@ fn iter_blas<'a>( blas.error_ident(), )); } - let vertex_buffer = match buffer_guard.get(mesh.vertex_buffer) { + let vertex_buffer = match buffer_guard.get(mesh.vertex_buffer).get() { Ok(buffer) => buffer, Err(_) => return Err(BuildAccelerationStructureError::InvalidBufferId), }; let vertex_pending = cmd_buf_data.trackers.buffers.set_single( - vertex_buffer, + &vertex_buffer, BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, ); let index_data = if let Some(index_id) = mesh.index_buffer { - let index_buffer = match buffer_guard.get(index_id) { + let index_buffer = match buffer_guard.get(index_id).get() { Ok(buffer) => buffer, Err(_) => return Err(BuildAccelerationStructureError::InvalidBufferId), }; @@ -859,7 +850,7 @@ fn iter_blas<'a>( )); } let data = cmd_buf_data.trackers.buffers.set_single( - index_buffer, + &index_buffer, hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, ); Some((index_buffer.clone(), data)) @@ -867,7 +858,7 @@ fn iter_blas<'a>( None }; let transform_data = if let Some(transform_id) = mesh.transform_buffer { - let transform_buffer = match buffer_guard.get(transform_id) { + let transform_buffer = match buffer_guard.get(transform_id).get() { Ok(buffer) => buffer, Err(_) => return Err(BuildAccelerationStructureError::InvalidBufferId), }; @@ -877,10 +868,10 @@ fn iter_blas<'a>( )); } let data = cmd_buf_data.trackers.buffers.set_single( - transform_buffer, + &transform_buffer, BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, ); - Some((transform_buffer.clone(), data)) + Some((transform_buffer, data)) } else { None }; @@ -903,13 +894,13 @@ fn iter_blas<'a>( Ok(()) } -/// Iterates over the buffers generated [iter_blas] and convert the barriers into hal barriers, and the triangles into hal [AccelerationStructureEntries] (and also some validation). +/// Iterates over the buffers generated [iter_blas] and convert the barriers into hal barriers, and the triangles into [hal::AccelerationStructureEntries] (and also some validation). fn iter_buffers<'a, 'b>( buf_storage: &'a mut BufferStorage<'b>, snatch_guard: &'a SnatchGuard, input_barriers: &mut Vec>, cmd_buf_data: &mut CommandBufferMutable, - buffer_guard: &RwLockReadGuard>, + buffer_guard: &RwLockReadGuard>>, scratch_buffer_blas_size: &mut u64, blas_storage: &mut BlasStorage<'a>, ) -> Result<(), BuildAccelerationStructureError> { @@ -946,7 +937,10 @@ fn iter_buffers<'a, 'b>( let vertex_buffer_offset = mesh.first_vertex as u64 * mesh.vertex_stride; cmd_buf_data.buffer_memory_init_actions.extend( vertex_buffer.initialization_status.read().create_action( - buffer_guard.get(mesh.vertex_buffer).unwrap(), + &buffer_guard + .get(mesh.vertex_buffer) + .get() + .map_err(|_| BuildAccelerationStructureError::InvalidBufferId)?, vertex_buffer_offset ..(vertex_buffer_offset + mesh.size.vertex_count as u64 * mesh.vertex_stride), diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 1f11ba0937..b6680333c2 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -4,6 +4,7 @@ use crate::command::{ }; use crate::init_tracker::BufferInitTrackerAction; use crate::pipeline::RenderPipeline; +use crate::resource::InvalidResourceError; use crate::snatch::SnatchGuard; use crate::{ api_log, @@ -45,7 +46,7 @@ use serde::Deserialize; use serde::Serialize; use std::sync::Arc; -use std::{borrow::Cow, fmt, iter, mem, num::NonZeroU32, ops::Range, str}; +use std::{borrow::Cow, fmt, iter, mem::size_of, num::NonZeroU32, ops::Range, str}; use super::render_command::ArcRenderCommand; use super::{ @@ -582,14 +583,6 @@ pub enum RenderPassErrorInner { InvalidParentEncoder, #[error("The format of the depth-stencil attachment ({0:?}) is not a depth-stencil format")] InvalidDepthStencilAttachmentFormat(wgt::TextureFormat), - #[error("Buffer {0:?} is invalid or destroyed")] - InvalidBuffer(id::BufferId), - #[error("Render pipeline {0:?} is invalid")] - InvalidPipeline(id::RenderPipelineId), - #[error("QuerySet {0:?} is invalid")] - InvalidQuerySet(id::QuerySetId), - #[error("Render bundle {0:?} is invalid")] - InvalidRenderBundle(id::RenderBundleId), #[error("The format of the {location} ({format:?}) is not resolvable")] UnsupportedResolveTargetFormat { location: AttachmentErrorLocation, @@ -635,8 +628,6 @@ pub enum RenderPassErrorInner { SurfaceTextureDropped, #[error("Not enough memory left for render pass")] OutOfMemory, - #[error("The bind group at index {0:?} is invalid")] - InvalidBindGroup(u32), #[error("Unable to clear non-present/read-only depth")] InvalidDepthOps, #[error("Unable to clear non-present/read-only stencil")] @@ -705,6 +696,8 @@ pub enum RenderPassErrorInner { DestroyedResource(#[from] DestroyedResourceError), #[error("The compute pass has already been ended and no further commands can be recorded")] PassEnded, + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } impl From for RenderPassErrorInner { @@ -1362,14 +1355,10 @@ impl Global { channel, }) = color_attachment { - let view = texture_views - .get_owned(*view_id) - .map_err(|_| CommandEncoderError::InvalidAttachmentId(*view_id))?; + let view = texture_views.get(*view_id).get()?; let resolve_target = if let Some(resolve_target_id) = resolve_target { - let rt_arc = texture_views.get_owned(*resolve_target_id).map_err(|_| { - CommandEncoderError::InvalidResolveTargetId(*resolve_target_id) - })?; + let rt_arc = texture_views.get(*resolve_target_id).get()?; Some(rt_arc) } else { @@ -1390,13 +1379,7 @@ impl Global { arc_desc.depth_stencil_attachment = if let Some(depth_stencil_attachment) = desc.depth_stencil_attachment { - let view = texture_views - .get_owned(depth_stencil_attachment.view) - .map_err(|_| { - CommandEncoderError::InvalidDepthStencilAttachmentId( - depth_stencil_attachment.view, - ) - })?; + let view = texture_views.get(depth_stencil_attachment.view).get()?; Some(ArcRenderPassDepthStencilAttachment { view, @@ -1408,9 +1391,7 @@ impl Global { }; arc_desc.timestamp_writes = if let Some(tw) = desc.timestamp_writes { - let query_set = query_sets.get_owned(tw.query_set).map_err(|_| { - CommandEncoderError::InvalidTimestampWritesQuerySetId(tw.query_set) - })?; + let query_set = query_sets.get(tw.query_set).get()?; Some(ArcPassTimestampWrites { query_set, @@ -1423,9 +1404,7 @@ impl Global { arc_desc.occlusion_query_set = if let Some(occlusion_query_set) = desc.occlusion_query_set { - let query_set = query_sets.get_owned(occlusion_query_set).map_err(|_| { - CommandEncoderError::InvalidOcclusionQuerySetId(occlusion_query_set) - })?; + let query_set = query_sets.get(occlusion_query_set).get()?; Some(query_set) } else { @@ -1446,12 +1425,13 @@ impl Global { let make_err = |e, arc_desc| (RenderPass::new(None, arc_desc), Some(e)); - let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { - Ok(cmd_buf) => cmd_buf, - Err(_) => return make_err(CommandEncoderError::Invalid, arc_desc), - }; + let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); - match cmd_buf.lock_encoder() { + match cmd_buf + .try_get() + .map_err(|e| e.into()) + .and_then(|mut cmd_buf_data| cmd_buf_data.lock_encoder()) + { Ok(_) => {} Err(e) => return make_err(e, arc_desc), }; @@ -1461,6 +1441,8 @@ impl Global { (RenderPass::new(Some(cmd_buf), arc_desc), err) } + /// Note that this differs from [`Self::render_pass_end`], it will + /// create a new pass, replay the commands and end the pass. #[doc(hidden)] #[cfg(any(feature = "serde", feature = "replay"))] pub fn render_pass_end_with_unresolved_commands( @@ -1476,15 +1458,11 @@ impl Global { #[cfg(feature = "trace")] { - let hub = &self.hub; - - let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid).map_pass_err(pass_scope)?, - }; - - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let cmd_buf = self + .hub + .command_buffers + .get(encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get().map_pass_err(pass_scope)?; if let Some(ref mut list) = cmd_buf_data.commands { list.push(crate::device::trace::Command::RunRenderPass { @@ -1528,29 +1506,26 @@ impl Global { }); }; - let hub = &self.hub; render_pass.base = Some(BasePass { label, - commands: super::RenderCommand::resolve_render_command_ids(hub, &commands)?, + commands: super::RenderCommand::resolve_render_command_ids(&self.hub, &commands)?, dynamic_offsets, string_data, push_constant_data, }); - if let Some(err) = encoder_error { - Err(RenderPassError { - scope: pass_scope, - inner: err.into(), - }) - } else { - self.render_pass_end(&mut render_pass) - } + self.render_pass_end(&mut render_pass) } - #[doc(hidden)] pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), RenderPassError> { let pass_scope = PassErrorScope::Pass; + let cmd_buf = pass + .parent + .as_ref() + .ok_or(RenderPassErrorInner::InvalidParentEncoder) + .map_pass_err(pass_scope)?; + let base = pass .base .take() @@ -1562,20 +1537,16 @@ impl Global { base.label.as_deref().unwrap_or("") ); - let Some(cmd_buf) = pass.parent.as_ref() else { - return Err(RenderPassErrorInner::InvalidParentEncoder).map_pass_err(pass_scope); - }; - cmd_buf.unlock_encoder().map_pass_err(pass_scope)?; - - let hal_label = hal_label(base.label.as_deref(), self.instance.flags); + let mut cmd_buf_data = cmd_buf.try_get().map_pass_err(pass_scope)?; + cmd_buf_data.unlock_encoder().map_pass_err(pass_scope)?; + let cmd_buf_data = &mut *cmd_buf_data; let device = &cmd_buf.device; let snatch_guard = &device.snatchable_lock.read(); - let (scope, pending_discard_init_fixups) = { - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let hal_label = hal_label(base.label.as_deref(), device.instance_flags); + let (scope, pending_discard_init_fixups) = { device.check_is_valid().map_pass_err(pass_scope)?; let encoder = &mut cmd_buf_data.encoder; @@ -1588,10 +1559,12 @@ impl Global { // We automatically keep extending command buffers over time, and because // we want to insert a command buffer _before_ what we're about to record, // we need to make sure to close the previous one. - encoder.close().map_pass_err(pass_scope)?; + encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?; // We will reset this to `Recording` if we succeed, acts as a fail-safe. *status = CommandEncoderStatus::Error; - encoder.open_pass(hal_label).map_pass_err(pass_scope)?; + encoder + .open_pass(hal_label, &cmd_buf.device) + .map_pass_err(pass_scope)?; let info = RenderPassInfo::start( device, @@ -1894,19 +1867,16 @@ impl Global { .finish(state.raw_encoder, state.snatch_guard) .map_pass_err(pass_scope)?; - encoder.close().map_pass_err(pass_scope)?; + encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?; (trackers, pending_discard_init_fixups) }; - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); - let encoder = &mut cmd_buf_data.encoder; let status = &mut cmd_buf_data.status; let tracker = &mut cmd_buf_data.trackers; { - let transit = encoder.open().map_pass_err(pass_scope)?; + let transit = encoder.open(&cmd_buf.device).map_pass_err(pass_scope)?; fixup_discarded_surfaces( pending_discard_init_fixups.into_iter(), @@ -1922,7 +1892,9 @@ impl Global { } *status = CommandEncoderStatus::Recording; - encoder.close_and_swap().map_pass_err(pass_scope)?; + encoder + .close_and_swap(&cmd_buf.device) + .map_pass_err(pass_scope)?; Ok(()) } @@ -1934,12 +1906,16 @@ fn set_bind_group( dynamic_offsets: &[DynamicOffset], index: u32, num_dynamic_offsets: usize, - bind_group: Arc, + bind_group: Option>, ) -> Result<(), RenderPassErrorInner> { - api_log!( - "RenderPass::set_bind_group {index} {}", - bind_group.error_ident() - ); + if bind_group.is_none() { + api_log!("RenderPass::set_bind_group {index} None"); + } else { + api_log!( + "RenderPass::set_bind_group {index} {}", + bind_group.as_ref().unwrap().error_ident() + ); + } let max_bind_groups = state.device.limits.max_bind_groups; if index >= max_bind_groups { @@ -1957,6 +1933,12 @@ fn set_bind_group( ); state.dynamic_offset_count += num_dynamic_offsets; + if bind_group.is_none() { + // TODO: Handle bind_group None. + return Ok(()); + } + + let bind_group = bind_group.unwrap(); let bind_group = state.tracker.bind_groups.insert_single(bind_group); bind_group.same_device_as(cmd_buf.as_ref())?; @@ -1999,7 +1981,7 @@ fn set_bind_group( state.raw_encoder.set_bind_group( pipeline_layout, index + i as u32, - raw_bg, + Some(raw_bg), &e.dynamic_offsets, ); } @@ -2073,7 +2055,7 @@ fn set_pipeline( state.raw_encoder.set_bind_group( pipeline.layout.raw(), start_index as u32 + i as u32, - raw_bg, + Some(raw_bg), &e.dynamic_offsets, ); } @@ -2442,8 +2424,8 @@ fn multi_draw_indirect( state.is_ready(indexed)?; let stride = match indexed { - false => mem::size_of::(), - true => mem::size_of::(), + false => size_of::(), + true => size_of::(), }; if count.is_some() { @@ -2520,8 +2502,8 @@ fn multi_draw_indirect_count( state.is_ready(indexed)?; let stride = match indexed { - false => mem::size_of::(), - true => mem::size_of::(), + false => size_of::(), + true => size_of::(), } as u64; state @@ -2760,11 +2742,7 @@ impl Global { buffer_id: id::Id, ) -> Result, RenderPassError> { let hub = &self.hub; - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| RenderPassErrorInner::InvalidBuffer(buffer_id)) - .map_pass_err(scope)?; + let buffer = hub.buffers.get(buffer_id).get().map_pass_err(scope)?; Ok(buffer) } @@ -2775,11 +2753,7 @@ impl Global { query_set_id: id::Id, ) -> Result, RenderPassError> { let hub = &self.hub; - let query_set = hub - .query_sets - .get(query_set_id) - .map_err(|_| RenderPassErrorInner::InvalidQuerySet(query_set_id)) - .map_pass_err(scope)?; + let query_set = hub.query_sets.get(query_set_id).get().map_pass_err(scope)?; Ok(query_set) } @@ -2788,7 +2762,7 @@ impl Global { &self, pass: &mut RenderPass, index: u32, - bind_group_id: id::BindGroupId, + bind_group_id: Option, offsets: &[DynamicOffset], ) -> Result<(), RenderPassError> { let scope = PassErrorScope::SetBindGroup; @@ -2808,12 +2782,18 @@ impl Global { return Ok(()); } - let hub = &self.hub; - let bind_group = hub - .bind_groups - .get(bind_group_id) - .map_err(|_| RenderPassErrorInner::InvalidBindGroup(index)) - .map_pass_err(scope)?; + let mut bind_group = None; + if bind_group_id.is_some() { + let bind_group_id = bind_group_id.unwrap(); + + let hub = &self.hub; + let bg = hub + .bind_groups + .get(bind_group_id) + .get() + .map_pass_err(scope)?; + bind_group = Some(bg); + } base.commands.push(ArcRenderCommand::SetBindGroup { index, @@ -2843,7 +2823,7 @@ impl Global { let pipeline = hub .render_pipelines .get(pipeline_id) - .map_err(|_| RenderPassErrorInner::InvalidPipeline(pipeline_id)) + .get() .map_pass_err(scope)?; base.commands.push(ArcRenderCommand::SetPipeline(pipeline)); @@ -3154,23 +3134,11 @@ impl Global { }; let base = pass.base_mut(scope)?; - // Don't use resolve_render_pass_buffer_id here, because we don't want to take the read-lock twice. - let hub = &self.hub; - let buffers = hub.buffers.read(); - let buffer = buffers - .get_owned(buffer_id) - .map_err(|_| RenderPassErrorInner::InvalidBuffer(buffer_id)) - .map_pass_err(scope)?; - let count_buffer = buffers - .get_owned(buffer_id) - .map_err(|_| RenderPassErrorInner::InvalidBuffer(count_buffer_id)) - .map_pass_err(scope)?; - base.commands .push(ArcRenderCommand::MultiDrawIndirectCount { - buffer, + buffer: self.resolve_render_pass_buffer_id(scope, buffer_id)?, offset, - count_buffer, + count_buffer: self.resolve_render_pass_buffer_id(scope, count_buffer_id)?, count_buffer_offset, max_count, indexed: false, @@ -3194,24 +3162,11 @@ impl Global { }; let base = pass.base_mut(scope)?; - // Don't use resolve_render_pass_buffer_id here, because we don't want to take the read-lock twice. - let hub = &self.hub; - let buffers = hub.buffers.read(); - let buffer = buffers - .get_owned(buffer_id) - .map_err(|_| RenderPassErrorInner::InvalidBuffer(buffer_id)) - .map_pass_err(scope)?; - - let count_buffer = buffers - .get_owned(buffer_id) - .map_err(|_| RenderPassErrorInner::InvalidBuffer(count_buffer_id)) - .map_pass_err(scope)?; - base.commands .push(ArcRenderCommand::MultiDrawIndirectCount { - buffer, + buffer: self.resolve_render_pass_buffer_id(scope, buffer_id)?, offset, - count_buffer, + count_buffer: self.resolve_render_pass_buffer_id(scope, count_buffer_id)?, count_buffer_offset, max_count, indexed: true, @@ -3355,10 +3310,7 @@ impl Global { let bundles = hub.render_bundles.read(); for &bundle_id in render_bundle_ids { - let bundle = bundles - .get_owned(bundle_id) - .map_err(|_| RenderPassErrorInner::InvalidRenderBundle(bundle_id)) - .map_pass_err(scope)?; + let bundle = bundles.get(bundle_id).get().map_pass_err(scope)?; base.commands.push(ArcRenderCommand::ExecuteBundle(bundle)); } diff --git a/wgpu-core/src/command/render_command.rs b/wgpu-core/src/command/render_command.rs index 891ee3cfbc..d4e2689d27 100644 --- a/wgpu-core/src/command/render_command.rs +++ b/wgpu-core/src/command/render_command.rs @@ -17,7 +17,7 @@ pub enum RenderCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group_id: id::BindGroupId, + bind_group_id: Option, }, SetPipeline(id::RenderPipelineId), SetIndexBuffer { @@ -129,9 +129,7 @@ impl RenderCommand { hub: &crate::hub::Hub, commands: &[RenderCommand], ) -> Result, super::RenderPassError> { - use super::{ - DrawKind, PassErrorScope, RenderCommandError, RenderPassError, RenderPassErrorInner, - }; + use super::{DrawKind, PassErrorScope, RenderPassError}; let buffers_guard = hub.buffers.read(); let bind_group_guard = hub.bind_groups.read(); @@ -139,240 +137,253 @@ impl RenderCommand { let pipelines_guard = hub.render_pipelines.read(); let render_bundles_guard = hub.render_bundles.read(); - let resolved_commands: Vec = commands - .iter() - .map(|c| -> Result { - Ok(match *c { - RenderCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group_id, - } => ArcRenderCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group: bind_group_guard.get_owned(bind_group_id).map_err(|_| { - RenderPassError { - scope: PassErrorScope::SetBindGroup, - inner: RenderPassErrorInner::InvalidBindGroup(index), + let resolved_commands: Vec = + commands + .iter() + .map(|c| -> Result { + Ok(match *c { + RenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group_id, + } => { + if bind_group_id.is_none() { + return Ok(ArcRenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: None, + }); } - })?, - }, - - RenderCommand::SetPipeline(pipeline_id) => ArcRenderCommand::SetPipeline( - pipelines_guard - .get_owned(pipeline_id) - .map_err(|_| RenderPassError { - scope: PassErrorScope::SetPipelineRender, - inner: RenderCommandError::InvalidPipelineId(pipeline_id).into(), - })?, - ), - - RenderCommand::SetPushConstant { - offset, - size_bytes, - values_offset, - stages, - } => ArcRenderCommand::SetPushConstant { - offset, - size_bytes, - values_offset, - stages, - }, - - RenderCommand::PushDebugGroup { color, len } => { - ArcRenderCommand::PushDebugGroup { color, len } - } - - RenderCommand::PopDebugGroup => ArcRenderCommand::PopDebugGroup, - - RenderCommand::InsertDebugMarker { color, len } => { - ArcRenderCommand::InsertDebugMarker { color, len } - } - - RenderCommand::WriteTimestamp { - query_set_id, - query_index, - } => ArcRenderCommand::WriteTimestamp { - query_set: query_set_guard.get_owned(query_set_id).map_err(|_| { - RenderPassError { - scope: PassErrorScope::WriteTimestamp, - inner: RenderPassErrorInner::InvalidQuerySet(query_set_id), - } - })?, - query_index, - }, - - RenderCommand::BeginPipelineStatisticsQuery { - query_set_id, - query_index, - } => ArcRenderCommand::BeginPipelineStatisticsQuery { - query_set: query_set_guard.get_owned(query_set_id).map_err(|_| { - RenderPassError { - scope: PassErrorScope::BeginPipelineStatisticsQuery, - inner: RenderPassErrorInner::InvalidQuerySet(query_set_id), - } - })?, - query_index, - }, - - RenderCommand::EndPipelineStatisticsQuery => { - ArcRenderCommand::EndPipelineStatisticsQuery - } - - RenderCommand::SetIndexBuffer { - buffer_id, - index_format, - offset, - size, - } => ArcRenderCommand::SetIndexBuffer { - buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { - RenderPassError { - scope: PassErrorScope::SetIndexBuffer, - inner: RenderCommandError::InvalidBufferId(buffer_id).into(), - } - })?, - index_format, - offset, - size, - }, - - RenderCommand::SetVertexBuffer { - slot, - buffer_id, - offset, - size, - } => ArcRenderCommand::SetVertexBuffer { - slot, - buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { - RenderPassError { - scope: PassErrorScope::SetVertexBuffer, - inner: RenderCommandError::InvalidBufferId(buffer_id).into(), - } - })?, - offset, - size, - }, - - RenderCommand::SetBlendConstant(color) => { - ArcRenderCommand::SetBlendConstant(color) - } - - RenderCommand::SetStencilReference(reference) => { - ArcRenderCommand::SetStencilReference(reference) - } - - RenderCommand::SetViewport { - rect, - depth_min, - depth_max, - } => ArcRenderCommand::SetViewport { - rect, - depth_min, - depth_max, - }, - - RenderCommand::SetScissor(scissor) => ArcRenderCommand::SetScissor(scissor), - - RenderCommand::Draw { - vertex_count, - instance_count, - first_vertex, - first_instance, - } => ArcRenderCommand::Draw { - vertex_count, - instance_count, - first_vertex, - first_instance, - }, - - RenderCommand::DrawIndexed { - index_count, - instance_count, - first_index, - base_vertex, - first_instance, - } => ArcRenderCommand::DrawIndexed { - index_count, - instance_count, - first_index, - base_vertex, - first_instance, - }, - - RenderCommand::MultiDrawIndirect { - buffer_id, - offset, - count, - indexed, - } => ArcRenderCommand::MultiDrawIndirect { - buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { - RenderPassError { - scope: PassErrorScope::Draw { - kind: if count.is_some() { - DrawKind::MultiDrawIndirect - } else { - DrawKind::DrawIndirect - }, - indexed, - }, - inner: RenderCommandError::InvalidBufferId(buffer_id).into(), + + let bind_group_id = bind_group_id.unwrap(); + let bg = bind_group_guard.get(bind_group_id).get().map_err(|e| { + RenderPassError { + scope: PassErrorScope::SetBindGroup, + inner: e.into(), + } + })?; + + ArcRenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: Some(bg), } - })?, - offset, - count, - indexed, - }, - - RenderCommand::MultiDrawIndirectCount { - buffer_id, - offset, - count_buffer_id, - count_buffer_offset, - max_count, - indexed, - } => { - let scope = PassErrorScope::Draw { - kind: DrawKind::MultiDrawIndirectCount, + } + + RenderCommand::SetPipeline(pipeline_id) => ArcRenderCommand::SetPipeline( + pipelines_guard.get(pipeline_id).get().map_err(|e| { + RenderPassError { + scope: PassErrorScope::SetPipelineRender, + inner: e.into(), + } + })?, + ), + + RenderCommand::SetPushConstant { + offset, + size_bytes, + values_offset, + stages, + } => ArcRenderCommand::SetPushConstant { + offset, + size_bytes, + values_offset, + stages, + }, + + RenderCommand::PushDebugGroup { color, len } => { + ArcRenderCommand::PushDebugGroup { color, len } + } + + RenderCommand::PopDebugGroup => ArcRenderCommand::PopDebugGroup, + + RenderCommand::InsertDebugMarker { color, len } => { + ArcRenderCommand::InsertDebugMarker { color, len } + } + + RenderCommand::WriteTimestamp { + query_set_id, + query_index, + } => ArcRenderCommand::WriteTimestamp { + query_set: query_set_guard.get(query_set_id).get().map_err(|e| { + RenderPassError { + scope: PassErrorScope::WriteTimestamp, + inner: e.into(), + } + })?, + query_index, + }, + + RenderCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + } => ArcRenderCommand::BeginPipelineStatisticsQuery { + query_set: query_set_guard.get(query_set_id).get().map_err(|e| { + RenderPassError { + scope: PassErrorScope::BeginPipelineStatisticsQuery, + inner: e.into(), + } + })?, + query_index, + }, + + RenderCommand::EndPipelineStatisticsQuery => { + ArcRenderCommand::EndPipelineStatisticsQuery + } + + RenderCommand::SetIndexBuffer { + buffer_id, + index_format, + offset, + size, + } => ArcRenderCommand::SetIndexBuffer { + buffer: buffers_guard.get(buffer_id).get().map_err(|e| { + RenderPassError { + scope: PassErrorScope::SetIndexBuffer, + inner: e.into(), + } + })?, + index_format, + offset, + size, + }, + + RenderCommand::SetVertexBuffer { + slot, + buffer_id, + offset, + size, + } => ArcRenderCommand::SetVertexBuffer { + slot, + buffer: buffers_guard.get(buffer_id).get().map_err(|e| { + RenderPassError { + scope: PassErrorScope::SetVertexBuffer, + inner: e.into(), + } + })?, + offset, + size, + }, + + RenderCommand::SetBlendConstant(color) => { + ArcRenderCommand::SetBlendConstant(color) + } + + RenderCommand::SetStencilReference(reference) => { + ArcRenderCommand::SetStencilReference(reference) + } + + RenderCommand::SetViewport { + rect, + depth_min, + depth_max, + } => ArcRenderCommand::SetViewport { + rect, + depth_min, + depth_max, + }, + + RenderCommand::SetScissor(scissor) => ArcRenderCommand::SetScissor(scissor), + + RenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + } => ArcRenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + }, + + RenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + } => ArcRenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + }, + + RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count, indexed, - }; - ArcRenderCommand::MultiDrawIndirectCount { - buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { + } => ArcRenderCommand::MultiDrawIndirect { + buffer: buffers_guard.get(buffer_id).get().map_err(|e| { RenderPassError { - scope, - inner: RenderCommandError::InvalidBufferId(buffer_id).into(), + scope: PassErrorScope::Draw { + kind: if count.is_some() { + DrawKind::MultiDrawIndirect + } else { + DrawKind::DrawIndirect + }, + indexed, + }, + inner: e.into(), } })?, offset, - count_buffer: buffers_guard.get_owned(count_buffer_id).map_err( - |_| RenderPassError { - scope, - inner: RenderCommandError::InvalidBufferId(count_buffer_id) - .into(), - }, - )?, + count, + indexed, + }, + + RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, count_buffer_offset, max_count, indexed, + } => { + let scope = PassErrorScope::Draw { + kind: DrawKind::MultiDrawIndirectCount, + indexed, + }; + ArcRenderCommand::MultiDrawIndirectCount { + buffer: buffers_guard.get(buffer_id).get().map_err(|e| { + RenderPassError { + scope, + inner: e.into(), + } + })?, + offset, + count_buffer: buffers_guard.get(count_buffer_id).get().map_err( + |e| RenderPassError { + scope, + inner: e.into(), + }, + )?, + count_buffer_offset, + max_count, + indexed, + } } - } - RenderCommand::BeginOcclusionQuery { query_index } => { - ArcRenderCommand::BeginOcclusionQuery { query_index } - } + RenderCommand::BeginOcclusionQuery { query_index } => { + ArcRenderCommand::BeginOcclusionQuery { query_index } + } - RenderCommand::EndOcclusionQuery => ArcRenderCommand::EndOcclusionQuery, + RenderCommand::EndOcclusionQuery => ArcRenderCommand::EndOcclusionQuery, - RenderCommand::ExecuteBundle(bundle) => ArcRenderCommand::ExecuteBundle( - render_bundles_guard - .get_owned(bundle) - .map_err(|_| RenderPassError { - scope: PassErrorScope::ExecuteBundle, - inner: RenderCommandError::InvalidRenderBundle(bundle).into(), + RenderCommand::ExecuteBundle(bundle) => ArcRenderCommand::ExecuteBundle( + render_bundles_guard.get(bundle).get().map_err(|e| { + RenderPassError { + scope: PassErrorScope::ExecuteBundle, + inner: e.into(), + } })?, - ), + ), + }) }) - }) - .collect::, RenderPassError>>()?; + .collect::, RenderPassError>>()?; Ok(resolved_commands) } } @@ -384,7 +395,7 @@ pub enum ArcRenderCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group: Arc, + bind_group: Option>, }, SetPipeline(Arc), SetIndexBuffer { @@ -464,11 +475,13 @@ pub enum ArcRenderCommand { indexed: bool, }, PushDebugGroup { + #[cfg_attr(target_os = "emscripten", allow(dead_code))] color: u32, len: usize, }, PopDebugGroup, InsertDebugMarker { + #[cfg_attr(target_os = "emscripten", allow(dead_code))] color: u32, len: usize, }, diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index de5ef9ed84..72eae50c25 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -12,11 +12,11 @@ use crate::{ TextureInitTrackerAction, }, resource::{ - DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError, ParentDevice, - Texture, TextureErrorDimension, + DestroyedResourceError, InvalidResourceError, MissingBufferUsageError, + MissingTextureUsageError, ParentDevice, Texture, TextureErrorDimension, }, snatch::SnatchGuard, - track::{TextureSelector, Tracker}, + track::TextureSelector, }; use arrayvec::ArrayVec; @@ -25,7 +25,7 @@ use wgt::{BufferAddress, BufferUsages, Extent3d, TextureUsages}; use std::sync::Arc; -use super::{memory_init::CommandBufferTextureMemoryActions, ClearError, CommandEncoder}; +use super::{ClearError, CommandBufferMutable}; pub type ImageCopyBuffer = wgt::ImageCopyBuffer; pub type ImageCopyTexture = wgt::ImageCopyTexture; @@ -41,10 +41,6 @@ pub enum CopySide { #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum TransferError { - #[error("BufferId {0:?} is invalid")] - InvalidBufferId(BufferId), - #[error("TextureId {0:?} is invalid")] - InvalidTextureId(TextureId), #[error("Source and destination cannot be the same buffer")] SameSourceDestinationBuffer, #[error(transparent)] @@ -150,6 +146,8 @@ pub enum CopyError { Transfer(#[from] TransferError), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } impl From for CopyError { @@ -408,9 +406,7 @@ pub(crate) fn validate_texture_copy_range( fn handle_texture_init( init_kind: MemoryInitKind, - encoder: &mut CommandEncoder, - trackers: &mut Tracker, - texture_memory_actions: &mut CommandBufferTextureMemoryActions, + cmd_buf_data: &mut CommandBufferMutable, device: &Device, copy_texture: &ImageCopyTexture, copy_size: &Extent3d, @@ -428,11 +424,13 @@ fn handle_texture_init( }; // Register the init action. - let immediate_inits = texture_memory_actions.register_init_action(&{ init_action }); + let immediate_inits = cmd_buf_data + .texture_memory_actions + .register_init_action(&{ init_action }); // In rare cases we may need to insert an init operation immediately onto the command buffer. if !immediate_inits.is_empty() { - let cmd_buf_raw = encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(device)?; for init in immediate_inits { clear_texture( &init.texture, @@ -441,7 +439,7 @@ fn handle_texture_init( layer_range: init.layer..(init.layer + 1), }, cmd_buf_raw, - &mut trackers.textures, + &mut cmd_buf_data.trackers.textures, &device.alignments, device.zero_buffer.as_ref(), snatch_guard, @@ -457,9 +455,7 @@ fn handle_texture_init( /// Ensure the source texture of a transfer is in the right initialization /// state, and record the state for after the transfer operation. fn handle_src_texture_init( - encoder: &mut CommandEncoder, - trackers: &mut Tracker, - texture_memory_actions: &mut CommandBufferTextureMemoryActions, + cmd_buf_data: &mut CommandBufferMutable, device: &Device, source: &ImageCopyTexture, copy_size: &Extent3d, @@ -468,9 +464,7 @@ fn handle_src_texture_init( ) -> Result<(), TransferError> { handle_texture_init( MemoryInitKind::NeedsInitializedMemory, - encoder, - trackers, - texture_memory_actions, + cmd_buf_data, device, source, copy_size, @@ -485,9 +479,7 @@ fn handle_src_texture_init( /// Ensure the destination texture of a transfer is in the right initialization /// state, and record the state for after the transfer operation. fn handle_dst_texture_init( - encoder: &mut CommandEncoder, - trackers: &mut Tracker, - texture_memory_actions: &mut CommandBufferTextureMemoryActions, + cmd_buf_data: &mut CommandBufferMutable, device: &Device, destination: &ImageCopyTexture, copy_size: &Extent3d, @@ -510,9 +502,7 @@ fn handle_dst_texture_init( handle_texture_init( dst_init_kind, - encoder, - trackers, - texture_memory_actions, + cmd_buf_data, device, destination, copy_size, @@ -542,17 +532,11 @@ impl Global { } let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; - - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + .get(command_encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; let device = &cmd_buf.device; device.check_is_valid()?; @@ -570,10 +554,7 @@ impl Global { let snatch_guard = device.snatchable_lock.read(); - let src_buffer = hub - .buffers - .get(source) - .map_err(|_| TransferError::InvalidBufferId(source))?; + let src_buffer = hub.buffers.get(source).get()?; src_buffer.same_device_as(cmd_buf.as_ref())?; @@ -589,10 +570,7 @@ impl Global { // expecting only a single barrier let src_barrier = src_pending.map(|pending| pending.into_hal(&src_buffer, &snatch_guard)); - let dst_buffer = hub - .buffers - .get(destination) - .map_err(|_| TransferError::InvalidBufferId(destination))?; + let dst_buffer = hub.buffers.get(destination).get()?; dst_buffer.same_device_as(cmd_buf.as_ref())?; @@ -684,7 +662,7 @@ impl Global { dst_offset: destination_offset, size: wgt::BufferSize::new(size).unwrap(), }; - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; let barriers = src_barrier .into_iter() .chain(dst_barrier) @@ -712,21 +690,15 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; + .get(command_encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; let device = &cmd_buf.device; device.check_is_valid()?; - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); - #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(TraceCommand::CopyBufferToTexture { @@ -736,20 +708,12 @@ impl Global { }); } - let encoder = &mut cmd_buf_data.encoder; - let tracker = &mut cmd_buf_data.trackers; - let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions; - let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions; - if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 { log::trace!("Ignoring copy_buffer_to_texture of size 0"); return Ok(()); } - let dst_texture = hub - .textures - .get(destination.texture) - .map_err(|_| TransferError::InvalidTextureId(destination.texture))?; + let dst_texture = hub.textures.get(destination.texture).get()?; dst_texture.same_device_as(cmd_buf.as_ref())?; @@ -768,9 +732,7 @@ impl Global { // have an easier time inserting "immediate-inits" that may be required // by prior discards in rare cases. handle_dst_texture_init( - encoder, - tracker, - texture_memory_actions, + &mut cmd_buf_data, device, destination, copy_size, @@ -778,14 +740,12 @@ impl Global { &snatch_guard, )?; - let src_buffer = hub - .buffers - .get(source.buffer) - .map_err(|_| TransferError::InvalidBufferId(source.buffer))?; + let src_buffer = hub.buffers.get(source.buffer).get()?; src_buffer.same_device_as(cmd_buf.as_ref())?; - let src_pending = tracker + let src_pending = cmd_buf_data + .trackers .buffers .set_single(&src_buffer, hal::BufferUses::COPY_SRC); @@ -795,10 +755,11 @@ impl Global { .map_err(TransferError::MissingBufferUsage)?; let src_barrier = src_pending.map(|pending| pending.into_hal(&src_buffer, &snatch_guard)); - let dst_pending = - tracker - .textures - .set_single(&dst_texture, dst_range, hal::TextureUses::COPY_DST); + let dst_pending = cmd_buf_data.trackers.textures.set_single( + &dst_texture, + dst_range, + hal::TextureUses::COPY_DST, + ); let dst_raw = dst_texture.try_raw(&snatch_guard)?; dst_texture .check_usage(TextureUsages::COPY_DST) @@ -835,11 +796,13 @@ impl Global { .map_err(TransferError::from)?; } - buffer_memory_init_actions.extend(src_buffer.initialization_status.read().create_action( - &src_buffer, - source.layout.offset..(source.layout.offset + required_buffer_bytes_in_copy), - MemoryInitKind::NeedsInitializedMemory, - )); + cmd_buf_data.buffer_memory_init_actions.extend( + src_buffer.initialization_status.read().create_action( + &src_buffer, + source.layout.offset..(source.layout.offset + required_buffer_bytes_in_copy), + MemoryInitKind::NeedsInitializedMemory, + ), + ); let regions = (0..array_layer_count) .map(|rel_array_layer| { @@ -855,7 +818,7 @@ impl Global { }) .collect::>(); - let cmd_buf_raw = encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.transition_textures(&dst_barrier); cmd_buf_raw.transition_buffers(src_barrier.as_slice()); @@ -880,21 +843,15 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; + .get(command_encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; let device = &cmd_buf.device; device.check_is_valid()?; - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); - #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(TraceCommand::CopyTextureToBuffer { @@ -903,20 +860,13 @@ impl Global { size: *copy_size, }); } - let encoder = &mut cmd_buf_data.encoder; - let tracker = &mut cmd_buf_data.trackers; - let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions; - let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions; if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 { log::trace!("Ignoring copy_texture_to_buffer of size 0"); return Ok(()); } - let src_texture = hub - .textures - .get(source.texture) - .map_err(|_| TransferError::InvalidTextureId(source.texture))?; + let src_texture = hub.textures.get(source.texture).get()?; src_texture.same_device_as(cmd_buf.as_ref())?; @@ -931,9 +881,7 @@ impl Global { // have an easier time inserting "immediate-inits" that may be required // by prior discards in rare cases. handle_src_texture_init( - encoder, - tracker, - texture_memory_actions, + &mut cmd_buf_data, device, source, copy_size, @@ -941,10 +889,11 @@ impl Global { &snatch_guard, )?; - let src_pending = - tracker - .textures - .set_single(&src_texture, src_range, hal::TextureUses::COPY_SRC); + let src_pending = cmd_buf_data.trackers.textures.set_single( + &src_texture, + src_range, + hal::TextureUses::COPY_SRC, + ); let src_raw = src_texture.try_raw(&snatch_guard)?; src_texture .check_usage(TextureUsages::COPY_SRC) @@ -966,14 +915,12 @@ impl Global { .map(|pending| pending.into_hal(src_raw)) .collect::>(); - let dst_buffer = hub - .buffers - .get(destination.buffer) - .map_err(|_| TransferError::InvalidBufferId(destination.buffer))?; + let dst_buffer = hub.buffers.get(destination.buffer).get()?; dst_buffer.same_device_as(cmd_buf.as_ref())?; - let dst_pending = tracker + let dst_pending = cmd_buf_data + .trackers .buffers .set_single(&dst_buffer, hal::BufferUses::COPY_DST); @@ -1011,11 +958,14 @@ impl Global { .map_err(TransferError::from)?; } - buffer_memory_init_actions.extend(dst_buffer.initialization_status.read().create_action( - &dst_buffer, - destination.layout.offset..(destination.layout.offset + required_buffer_bytes_in_copy), - MemoryInitKind::ImplicitlyInitialized, - )); + cmd_buf_data.buffer_memory_init_actions.extend( + dst_buffer.initialization_status.read().create_action( + &dst_buffer, + destination.layout.offset + ..(destination.layout.offset + required_buffer_bytes_in_copy), + MemoryInitKind::ImplicitlyInitialized, + ), + ); let regions = (0..array_layer_count) .map(|rel_array_layer| { @@ -1030,7 +980,7 @@ impl Global { } }) .collect::>(); - let cmd_buf_raw = encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.transition_buffers(dst_barrier.as_slice()); cmd_buf_raw.transition_textures(&src_barrier); @@ -1060,23 +1010,17 @@ impl Global { let hub = &self.hub; - let cmd_buf = match hub + let cmd_buf = hub .command_buffers - .get(command_encoder_id.into_command_buffer_id()) - { - Ok(cmd_buf) => cmd_buf, - Err(_) => return Err(CommandEncoderError::Invalid.into()), - }; - cmd_buf.check_recording()?; + .get(command_encoder_id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.try_get()?; + cmd_buf_data.check_recording()?; let device = &cmd_buf.device; device.check_is_valid()?; let snatch_guard = device.snatchable_lock.read(); - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); - #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(TraceCommand::CopyTextureToTexture { @@ -1085,23 +1029,14 @@ impl Global { size: *copy_size, }); } - let encoder = &mut cmd_buf_data.encoder; - let tracker = &mut cmd_buf_data.trackers; - let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions; if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 { log::trace!("Ignoring copy_texture_to_texture of size 0"); return Ok(()); } - let src_texture = hub - .textures - .get(source.texture) - .map_err(|_| TransferError::InvalidTextureId(source.texture))?; - let dst_texture = hub - .textures - .get(destination.texture) - .map_err(|_| TransferError::InvalidTextureId(source.texture))?; + let src_texture = hub.textures.get(source.texture).get()?; + let dst_texture = hub.textures.get(destination.texture).get()?; src_texture.same_device_as(cmd_buf.as_ref())?; dst_texture.same_device_as(cmd_buf.as_ref())?; @@ -1143,9 +1078,7 @@ impl Global { // have an easier time inserting "immediate-inits" that may be required // by prior discards in rare cases. handle_src_texture_init( - encoder, - tracker, - texture_memory_actions, + &mut cmd_buf_data, device, source, copy_size, @@ -1153,9 +1086,7 @@ impl Global { &snatch_guard, )?; handle_dst_texture_init( - encoder, - tracker, - texture_memory_actions, + &mut cmd_buf_data, device, destination, copy_size, @@ -1209,7 +1140,7 @@ impl Global { } }) .collect::>(); - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.transition_textures(&barriers); cmd_buf_raw.copy_texture_to_texture( diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 2eb1466d65..e1d3f43f2d 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -6,7 +6,8 @@ use crate::{ self, BindGroupEntry, BindingResource, BufferBinding, ResolvedBindGroupDescriptor, ResolvedBindGroupEntry, ResolvedBindingResource, ResolvedBufferBinding, }, - command, conv, + command::{self, CommandBuffer}, + conv, device::{bgl, life::WaitIdleError, DeviceError, DeviceLostClosure, DeviceLostReason}, global::Global, hal_api::HalApi, @@ -19,14 +20,19 @@ use crate::{ present, resource::{ self, BufferAccessError, BufferAccessResult, BufferMapOperation, CreateBufferError, + Fallible, }, storage::Storage, - Label, + Label, LabelHelpers, }; use wgt::{BufferAddress, TextureFormat}; -use std::{borrow::Cow, ptr::NonNull, sync::atomic::Ordering}; +use std::{ + borrow::Cow, + ptr::NonNull, + sync::{atomic::Ordering, Arc}, +}; use super::{ImplicitPipelineIds, UserClosures}; @@ -35,18 +41,10 @@ impl Global { &self, adapter_id: AdapterId, surface_id: SurfaceId, - ) -> Result { - let hub = &self.hub; - - let surface_guard = self.surfaces.read(); - let adapter_guard = hub.adapters.read(); - let adapter = adapter_guard - .get(adapter_id) - .map_err(|_| instance::IsSurfaceSupportedError::InvalidAdapter)?; - let surface = surface_guard - .get(surface_id) - .map_err(|_| instance::IsSurfaceSupportedError::InvalidSurface)?; - Ok(adapter.is_surface_supported(surface)) + ) -> bool { + let surface = self.surfaces.get(surface_id); + let adapter = self.hub.adapters.get(adapter_id); + adapter.is_surface_supported(&surface) } pub fn surface_get_capabilities( @@ -71,63 +69,30 @@ impl Global { }) } - fn fetch_adapter_and_surface< - F: FnOnce(&Adapter, &Surface) -> Result, - B, - >( + fn fetch_adapter_and_surface B, B>( &self, surface_id: SurfaceId, adapter_id: AdapterId, get_supported_callback: F, - ) -> Result { - let hub = &self.hub; - - let surface_guard = self.surfaces.read(); - let adapter_guard = hub.adapters.read(); - let adapter = adapter_guard - .get(adapter_id) - .map_err(|_| instance::GetSurfaceSupportError::InvalidAdapter)?; - let surface = surface_guard - .get(surface_id) - .map_err(|_| instance::GetSurfaceSupportError::InvalidSurface)?; - - get_supported_callback(adapter, surface) + ) -> B { + let surface = self.surfaces.get(surface_id); + let adapter = self.hub.adapters.get(adapter_id); + get_supported_callback(&adapter, &surface) } - pub fn device_features(&self, device_id: DeviceId) -> Result { - let hub = &self.hub; - - let device = hub - .devices - .get(device_id) - .map_err(|_| DeviceError::InvalidDeviceId)?; - - Ok(device.features) + pub fn device_features(&self, device_id: DeviceId) -> wgt::Features { + let device = self.hub.devices.get(device_id); + device.features } - pub fn device_limits(&self, device_id: DeviceId) -> Result { - let hub = &self.hub; - - let device = hub - .devices - .get(device_id) - .map_err(|_| DeviceError::InvalidDeviceId)?; - - Ok(device.limits.clone()) + pub fn device_limits(&self, device_id: DeviceId) -> wgt::Limits { + let device = self.hub.devices.get(device_id); + device.limits.clone() } - pub fn device_downlevel_properties( - &self, - device_id: DeviceId, - ) -> Result { - let hub = &self.hub; - - let device = hub - .devices - .get(device_id) - .map_err(|_| DeviceError::InvalidDeviceId)?; - - Ok(device.downlevel.clone()) + pub fn device_downlevel_properties(&self, device_id: DeviceId) -> wgt::DownlevelCapabilities { + let device = self.hub.devices.get(device_id); + device.downlevel.clone() } pub fn device_create_buffer( @@ -139,15 +104,10 @@ impl Global { profiling::scope!("Device::create_buffer"); let hub = &self.hub; - let fid = hub.buffers.prepare(device_id.backend(), id_in); + let fid = hub.buffers.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => { - break 'error DeviceError::InvalidDeviceId.into(); - } - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -166,7 +126,7 @@ impl Global { } }; - let id = fid.assign(buffer); + let id = fid.assign(Fallible::Valid(buffer)); api_log!( "Device::create_buffer({:?}{}) -> {id:?}", @@ -181,7 +141,7 @@ impl Global { return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -213,32 +173,34 @@ impl Global { /// [`device_create_buffer`]: Global::device_create_buffer /// [`usage`]: https://www.w3.org/TR/webgpu/#dom-gputexturedescriptor-usage /// [`wgpu_types::BufferUsages`]: wgt::BufferUsages - pub fn create_buffer_error(&self, backend: wgt::Backend, id_in: Option) { - let hub = &self.hub; - let fid = hub.buffers.prepare(backend, id_in); - - fid.assign_error(); + pub fn create_buffer_error( + &self, + id_in: Option, + desc: &resource::BufferDescriptor, + ) { + let fid = self.hub.buffers.prepare(id_in); + fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); } pub fn create_render_bundle_error( &self, - backend: wgt::Backend, id_in: Option, + desc: &command::RenderBundleDescriptor, ) { - let hub = &self.hub; - let fid = hub.render_bundles.prepare(backend, id_in); - - fid.assign_error(); + let fid = self.hub.render_bundles.prepare(id_in); + fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); } /// Assign `id_in` an error with the given `label`. /// /// See `create_buffer_error` for more context and explanation. - pub fn create_texture_error(&self, backend: wgt::Backend, id_in: Option) { - let hub = &self.hub; - let fid = hub.textures.prepare(backend, id_in); - - fid.assign_error(); + pub fn create_texture_error( + &self, + id_in: Option, + desc: &resource::TextureDescriptor, + ) { + let fid = self.hub.textures.prepare(id_in); + fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); } #[cfg(feature = "replay")] @@ -250,10 +212,7 @@ impl Global { ) -> BufferAccessResult { let hub = &self.hub; - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| BufferAccessError::InvalidBufferId(buffer_id))?; + let buffer = hub.buffers.get(buffer_id).get()?; let device = &buffer.device; @@ -270,21 +229,27 @@ impl Global { let snatch_guard = device.snatchable_lock.read(); let raw_buf = buffer.try_raw(&snatch_guard)?; - unsafe { - let mapping = device + + let mapping = unsafe { + device .raw() .map_buffer(raw_buf, offset..offset + data.len() as u64) - .map_err(DeviceError::from)?; - std::ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len()); - if !mapping.is_coherent { - #[allow(clippy::single_range_in_vec_init)] + } + .map_err(|e| device.handle_hal_error(e))?; + + unsafe { std::ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len()) }; + + if !mapping.is_coherent { + #[allow(clippy::single_range_in_vec_init)] + unsafe { device .raw() - .flush_mapped_ranges(raw_buf, &[offset..offset + data.len() as u64]); - } - device.raw().unmap_buffer(raw_buf); + .flush_mapped_ranges(raw_buf, &[offset..offset + data.len() as u64]) + }; } + unsafe { device.raw().unmap_buffer(raw_buf) }; + Ok(()) } @@ -294,10 +259,7 @@ impl Global { let hub = &self.hub; - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| resource::DestroyError::Invalid)?; + let buffer = hub.buffers.get(buffer_id).get()?; #[cfg(feature = "trace")] if let Some(trace) = buffer.device.trace.lock().as_mut() { @@ -318,9 +280,9 @@ impl Global { let hub = &self.hub; - let buffer = match hub.buffers.unregister(buffer_id) { - Some(buffer) => buffer, - None => { + let buffer = match hub.buffers.remove(buffer_id).get() { + Ok(buffer) => buffer, + Err(_) => { return; } }; @@ -346,13 +308,10 @@ impl Global { let hub = &self.hub; - let fid = hub.textures.prepare(device_id.backend(), id_in); + let fid = hub.textures.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -364,7 +323,7 @@ impl Global { Err(error) => break 'error error, }; - let id = fid.assign(texture); + let id = fid.assign(Fallible::Valid(texture)); api_log!("Device::create_texture({desc:?}) -> {id:?}"); return (id, None); @@ -372,7 +331,7 @@ impl Global { log::error!("Device::create_texture error: {error}"); - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -392,13 +351,10 @@ impl Global { let hub = &self.hub; - let fid = hub.textures.prepare(device_id.backend(), id_in); + let fid = hub.textures.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); // NB: Any change done through the raw texture handle will not be // recorded in the replay @@ -412,7 +368,7 @@ impl Global { Err(error) => break 'error error, }; - let id = fid.assign(texture); + let id = fid.assign(Fallible::Valid(texture)); api_log!("Device::create_texture({desc:?}) -> {id:?}"); return (id, None); @@ -420,7 +376,7 @@ impl Global { log::error!("Device::create_texture error: {error}"); - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -439,33 +395,23 @@ impl Global { profiling::scope!("Device::create_buffer"); let hub = &self.hub; - let fid = hub.buffers.prepare(A::VARIANT, id_in); + let fid = hub.buffers.prepare(id_in); - let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; - - // NB: Any change done through the raw buffer handle will not be - // recorded in the replay - #[cfg(feature = "trace")] - if let Some(trace) = device.trace.lock().as_mut() { - trace.add(trace::Action::CreateBuffer(fid.id(), desc.clone())); - } + let device = self.hub.devices.get(device_id); - let buffer = device.create_buffer_from_hal(Box::new(hal_buffer), desc); - - let id = fid.assign(buffer); - api_log!("Device::create_buffer -> {id:?}"); + // NB: Any change done through the raw buffer handle will not be + // recorded in the replay + #[cfg(feature = "trace")] + if let Some(trace) = device.trace.lock().as_mut() { + trace.add(trace::Action::CreateBuffer(fid.id(), desc.clone())); + } - return (id, None); - }; + let buffer = device.create_buffer_from_hal(Box::new(hal_buffer), desc); - log::error!("Device::create_buffer error: {error}"); + let id = fid.assign(buffer); + api_log!("Device::create_buffer -> {id:?}"); - let id = fid.assign_error(); - (id, Some(error)) + (id, None) } pub fn texture_destroy(&self, texture_id: id::TextureId) -> Result<(), resource::DestroyError> { @@ -474,10 +420,7 @@ impl Global { let hub = &self.hub; - let texture = hub - .textures - .get(texture_id) - .map_err(|_| resource::DestroyError::Invalid)?; + let texture = hub.textures.get(texture_id).get()?; #[cfg(feature = "trace")] if let Some(trace) = texture.device.trace.lock().as_mut() { @@ -493,9 +436,10 @@ impl Global { let hub = &self.hub; - if let Some(_texture) = hub.textures.unregister(texture_id) { - #[cfg(feature = "trace")] - if let Some(t) = _texture.device.trace.lock().as_mut() { + let _texture = hub.textures.remove(texture_id); + #[cfg(feature = "trace")] + if let Ok(texture) = _texture.get() { + if let Some(t) = texture.device.trace.lock().as_mut() { t.add(trace::Action::DestroyTexture(texture_id)); } } @@ -511,14 +455,12 @@ impl Global { let hub = &self.hub; - let fid = hub.texture_views.prepare(texture_id.backend(), id_in); + let fid = hub.texture_views.prepare(id_in); let error = 'error: { - let texture = match hub.textures.get(texture_id) { + let texture = match hub.textures.get(texture_id).get() { Ok(texture) => texture, - Err(_) => { - break 'error resource::CreateTextureViewError::InvalidTextureId(texture_id) - } + Err(e) => break 'error e.into(), }; let device = &texture.device; @@ -536,7 +478,7 @@ impl Global { Err(e) => break 'error e, }; - let id = fid.assign(view); + let id = fid.assign(Fallible::Valid(view)); api_log!("Texture::create_view({texture_id:?}) -> {id:?}"); @@ -544,7 +486,7 @@ impl Global { }; log::error!("Texture::create_view({texture_id:?}) error: {error}"); - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -557,9 +499,11 @@ impl Global { let hub = &self.hub; - if let Some(_view) = hub.texture_views.unregister(texture_view_id) { - #[cfg(feature = "trace")] - if let Some(t) = _view.device.trace.lock().as_mut() { + let _view = hub.texture_views.remove(texture_view_id); + + #[cfg(feature = "trace")] + if let Ok(view) = _view.get() { + if let Some(t) = view.device.trace.lock().as_mut() { t.add(trace::Action::DestroyTextureView(texture_view_id)); } } @@ -575,13 +519,10 @@ impl Global { profiling::scope!("Device::create_sampler"); let hub = &self.hub; - let fid = hub.samplers.prepare(device_id.backend(), id_in); + let fid = hub.samplers.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -593,13 +534,13 @@ impl Global { Err(e) => break 'error e, }; - let id = fid.assign(sampler); + let id = fid.assign(Fallible::Valid(sampler)); api_log!("Device::create_sampler -> {id:?}"); return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -609,9 +550,11 @@ impl Global { let hub = &self.hub; - if let Some(_sampler) = hub.samplers.unregister(sampler_id) { - #[cfg(feature = "trace")] - if let Some(t) = _sampler.device.trace.lock().as_mut() { + let _sampler = hub.samplers.remove(sampler_id); + + #[cfg(feature = "trace")] + if let Ok(sampler) = _sampler.get() { + if let Some(t) = sampler.device.trace.lock().as_mut() { t.add(trace::Action::DestroySampler(sampler_id)); } } @@ -629,13 +572,10 @@ impl Global { profiling::scope!("Device::create_bind_group_layout"); let hub = &self.hub; - let fid = hub.bind_group_layouts.prepare(device_id.backend(), id_in); + let fid = hub.bind_group_layouts.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -666,14 +606,13 @@ impl Global { Err(e) => break 'error e, }; - let id = fid.assign(layout.clone()); + let id = fid.assign(Fallible::Valid(layout.clone())); api_log!("Device::create_bind_group_layout -> {id:?}"); return (id, None); }; - let fid = hub.bind_group_layouts.prepare(device_id.backend(), id_in); - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -683,9 +622,11 @@ impl Global { let hub = &self.hub; - if let Some(_layout) = hub.bind_group_layouts.unregister(bind_group_layout_id) { - #[cfg(feature = "trace")] - if let Some(t) = _layout.device.trace.lock().as_mut() { + let _layout = hub.bind_group_layouts.remove(bind_group_layout_id); + + #[cfg(feature = "trace")] + if let Ok(layout) = _layout.get() { + if let Some(t) = layout.device.trace.lock().as_mut() { t.add(trace::Action::DestroyBindGroupLayout(bind_group_layout_id)); } } @@ -703,13 +644,10 @@ impl Global { profiling::scope!("Device::create_pipeline_layout"); let hub = &self.hub; - let fid = hub.pipeline_layouts.prepare(device_id.backend(), id_in); + let fid = hub.pipeline_layouts.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -720,19 +658,13 @@ impl Global { let bind_group_layouts_guard = hub.bind_group_layouts.read(); desc.bind_group_layouts .iter() - .map(|bgl_id| { - bind_group_layouts_guard.get_owned(*bgl_id).map_err(|_| { - binding_model::CreatePipelineLayoutError::InvalidBindGroupLayoutId( - *bgl_id, - ) - }) - }) + .map(|bgl_id| bind_group_layouts_guard.get(*bgl_id).get()) .collect::, _>>() }; let bind_group_layouts = match bind_group_layouts { Ok(bind_group_layouts) => bind_group_layouts, - Err(e) => break 'error e, + Err(e) => break 'error e.into(), }; let desc = binding_model::ResolvedPipelineLayoutDescriptor { @@ -746,12 +678,12 @@ impl Global { Err(e) => break 'error e, }; - let id = fid.assign(layout); + let id = fid.assign(Fallible::Valid(layout)); api_log!("Device::create_pipeline_layout -> {id:?}"); return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -760,9 +692,12 @@ impl Global { api_log!("PipelineLayout::drop {pipeline_layout_id:?}"); let hub = &self.hub; - if let Some(_layout) = hub.pipeline_layouts.unregister(pipeline_layout_id) { - #[cfg(feature = "trace")] - if let Some(t) = _layout.device.trace.lock().as_mut() { + + let _layout = hub.pipeline_layouts.remove(pipeline_layout_id); + + #[cfg(feature = "trace")] + if let Ok(layout) = _layout.get() { + if let Some(t) = layout.device.trace.lock().as_mut() { t.add(trace::Action::DestroyPipelineLayout(pipeline_layout_id)); } } @@ -777,89 +712,91 @@ impl Global { profiling::scope!("Device::create_bind_group"); let hub = &self.hub; - let fid = hub.bind_groups.prepare(device_id.backend(), id_in); + let fid = hub.bind_groups.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { trace.add(trace::Action::CreateBindGroup(fid.id(), desc.clone())); } - let layout = match hub.bind_group_layouts.get(desc.layout) { + let layout = match hub.bind_group_layouts.get(desc.layout).get() { Ok(layout) => layout, - Err(..) => break 'error binding_model::CreateBindGroupError::InvalidLayout, + Err(e) => break 'error e.into(), }; - fn map_entry<'a>( + fn resolve_entry<'a>( e: &BindGroupEntry<'a>, - buffer_storage: &Storage, - sampler_storage: &Storage, - texture_view_storage: &Storage, - tlas_storage: &Storage, + buffer_storage: &Storage>, + sampler_storage: &Storage>, + texture_view_storage: &Storage>, + tlas_storage: &Storage>, ) -> Result, binding_model::CreateBindGroupError> { - let map_buffer = |bb: &BufferBinding| { + let resolve_buffer = |bb: &BufferBinding| { buffer_storage - .get_owned(bb.buffer_id) + .get(bb.buffer_id) + .get() .map(|buffer| ResolvedBufferBinding { buffer, offset: bb.offset, size: bb.size, }) - .map_err(|_| { - binding_model::CreateBindGroupError::InvalidBufferId(bb.buffer_id) - }) + .map_err(binding_model::CreateBindGroupError::from) }; - let map_sampler = |id: &id::SamplerId| { + let resolve_sampler = |id: &id::SamplerId| { sampler_storage - .get_owned(*id) - .map_err(|_| binding_model::CreateBindGroupError::InvalidSamplerId(*id)) + .get(*id) + .get() + .map_err(binding_model::CreateBindGroupError::from) }; - let map_view = |id: &id::TextureViewId| { + let resolve_view = |id: &id::TextureViewId| { texture_view_storage - .get_owned(*id) - .map_err(|_| binding_model::CreateBindGroupError::InvalidTextureViewId(*id)) + .get(*id) + .get() + .map_err(binding_model::CreateBindGroupError::from) }; - let map_tlas = |id: &id::TlasId| { + let resolve_tlas = |id: &id::TlasId| { tlas_storage - .get_owned(*id) - .map_err(|_| binding_model::CreateBindGroupError::InvalidTlasId(*id)) + .get(*id) + .get() + .map_err(binding_model::CreateBindGroupError::from) }; let resource = match e.resource { BindingResource::Buffer(ref buffer) => { - ResolvedBindingResource::Buffer(map_buffer(buffer)?) + ResolvedBindingResource::Buffer(resolve_buffer(buffer)?) } BindingResource::BufferArray(ref buffers) => { let buffers = buffers .iter() - .map(map_buffer) + .map(resolve_buffer) .collect::, _>>()?; ResolvedBindingResource::BufferArray(Cow::Owned(buffers)) } BindingResource::Sampler(ref sampler) => { - ResolvedBindingResource::Sampler(map_sampler(sampler)?) + ResolvedBindingResource::Sampler(resolve_sampler(sampler)?) } BindingResource::SamplerArray(ref samplers) => { let samplers = samplers .iter() - .map(map_sampler) + .map(resolve_sampler) .collect::, _>>()?; ResolvedBindingResource::SamplerArray(Cow::Owned(samplers)) } BindingResource::TextureView(ref view) => { - ResolvedBindingResource::TextureView(map_view(view)?) + ResolvedBindingResource::TextureView(resolve_view(view)?) } BindingResource::TextureViewArray(ref views) => { - let views = views.iter().map(map_view).collect::, _>>()?; + let views = views + .iter() + .map(resolve_view) + .collect::, _>>()?; ResolvedBindingResource::TextureViewArray(Cow::Owned(views)) } BindingResource::AccelerationStructure(ref tlas) => { - ResolvedBindingResource::AccelerationStructure(map_tlas(tlas)?) + ResolvedBindingResource::AccelerationStructure(resolve_tlas(tlas)?) } }; Ok(ResolvedBindGroupEntry { @@ -876,7 +813,7 @@ impl Global { desc.entries .iter() .map(|e| { - map_entry( + resolve_entry( e, &buffer_guard, &sampler_guard, @@ -902,14 +839,14 @@ impl Global { Err(e) => break 'error e, }; - let id = fid.assign(bind_group); + let id = fid.assign(Fallible::Valid(bind_group)); api_log!("Device::create_bind_group -> {id:?}"); return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -919,8 +856,10 @@ impl Global { let hub = &self.hub; - if let Some(_bind_group) = hub.bind_groups.unregister(bind_group_id) { - #[cfg(feature = "trace")] + let _bind_group = hub.bind_groups.remove(bind_group_id); + + #[cfg(feature = "trace")] + if let Ok(_bind_group) = _bind_group.get() { if let Some(t) = _bind_group.device.trace.lock().as_mut() { t.add(trace::Action::DestroyBindGroup(bind_group_id)); } @@ -954,13 +893,10 @@ impl Global { profiling::scope!("Device::create_shader_module"); let hub = &self.hub; - let fid = hub.shader_modules.prepare(device_id.backend(), id_in); + let fid = hub.shader_modules.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -999,14 +935,14 @@ impl Global { Err(e) => break 'error e, }; - let id = fid.assign(shader); + let id = fid.assign(Fallible::Valid(shader)); api_log!("Device::create_shader_module -> {id:?}"); return (id, None); }; log::error!("Device::create_shader_module error: {error}"); - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -1029,13 +965,10 @@ impl Global { profiling::scope!("Device::create_shader_module"); let hub = &self.hub; - let fid = hub.shader_modules.prepare(device_id.backend(), id_in); + let fid = hub.shader_modules.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -1053,14 +986,14 @@ impl Global { Ok(shader) => shader, Err(e) => break 'error e, }; - let id = fid.assign(shader); + let id = fid.assign(Fallible::Valid(shader)); api_log!("Device::create_shader_module_spirv -> {id:?}"); return (id, None); }; log::error!("Device::create_shader_module_spirv error: {error}"); - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -1070,12 +1003,13 @@ impl Global { let hub = &self.hub; - if let Some(shader_module) = hub.shader_modules.unregister(shader_module_id) { - #[cfg(feature = "trace")] + let _shader_module = hub.shader_modules.remove(shader_module_id); + + #[cfg(feature = "trace")] + if let Ok(shader_module) = _shader_module.get() { if let Some(t) = shader_module.device.trace.lock().as_mut() { t.add(trace::Action::DestroyShaderModule(shader_module_id)); } - drop(shader_module) } } @@ -1088,17 +1022,13 @@ impl Global { profiling::scope!("Device::create_command_encoder"); let hub = &self.hub; - let fid = hub.command_buffers.prepare( - device_id.backend(), - id_in.map(|id| id.into_command_buffer_id()), - ); + let fid = hub + .command_buffers + .prepare(id_in.map(|id| id.into_command_buffer_id())); - let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId, - }; + let device = self.hub.devices.get(device_id); + let error = 'error: { let command_buffer = match device.create_command_encoder(&desc.label) { Ok(command_buffer) => command_buffer, Err(e) => break 'error e, @@ -1109,7 +1039,7 @@ impl Global { return (id.into_command_encoder_id(), None); }; - let id = fid.assign_error(); + let id = fid.assign(Arc::new(CommandBuffer::new_invalid(&device, &desc.label))); (id.into_command_encoder_id(), Some(error)) } @@ -1119,12 +1049,9 @@ impl Global { let hub = &self.hub; - if let Some(cmd_buf) = hub + let _cmd_buf = hub .command_buffers - .unregister(command_encoder_id.into_command_buffer_id()) - { - cmd_buf.data.lock().as_mut().unwrap().encoder.discard(); - } + .remove(command_encoder_id.into_command_buffer_id()); } pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) { @@ -1160,19 +1087,10 @@ impl Global { let hub = &self.hub; - let fid = hub - .render_bundles - .prepare(bundle_encoder.parent().backend(), id_in); + let fid = hub.render_bundles.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(bundle_encoder.parent()) { - Ok(device) => device, - Err(_) => { - break 'error command::RenderBundleError::from_device_error( - DeviceError::InvalidDeviceId, - ); - } - }; + let device = self.hub.devices.get(bundle_encoder.parent()); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -1193,13 +1111,13 @@ impl Global { Err(e) => break 'error e, }; - let id = fid.assign(render_bundle); + let id = fid.assign(Fallible::Valid(render_bundle)); api_log!("RenderBundleEncoder::finish -> {id:?}"); return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -1209,9 +1127,11 @@ impl Global { let hub = &self.hub; - if let Some(_bundle) = hub.render_bundles.unregister(render_bundle_id) { - #[cfg(feature = "trace")] - if let Some(t) = _bundle.device.trace.lock().as_mut() { + let _bundle = hub.render_bundles.remove(render_bundle_id); + + #[cfg(feature = "trace")] + if let Ok(bundle) = _bundle.get() { + if let Some(t) = bundle.device.trace.lock().as_mut() { t.add(trace::Action::DestroyRenderBundle(render_bundle_id)); } } @@ -1226,13 +1146,10 @@ impl Global { profiling::scope!("Device::create_query_set"); let hub = &self.hub; - let fid = hub.query_sets.prepare(device_id.backend(), id_in); + let fid = hub.query_sets.prepare(id_in); let error = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -1247,13 +1164,13 @@ impl Global { Err(err) => break 'error err, }; - let id = fid.assign(query_set); + let id = fid.assign(Fallible::Valid(query_set)); api_log!("Device::create_query_set -> {id:?}"); return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -1263,9 +1180,11 @@ impl Global { let hub = &self.hub; - if let Some(_query_set) = hub.query_sets.unregister(query_set_id) { - #[cfg(feature = "trace")] - if let Some(trace) = _query_set.device.trace.lock().as_mut() { + let _query_set = hub.query_sets.remove(query_set_id); + + #[cfg(feature = "trace")] + if let Ok(query_set) = _query_set.get() { + if let Some(trace) = query_set.device.trace.lock().as_mut() { trace.add(trace::Action::DestroyQuerySet(query_set_id)); } } @@ -1288,7 +1207,7 @@ impl Global { let missing_implicit_pipeline_ids = desc.layout.is_none() && id_in.is_some() && implicit_pipeline_ids.is_none(); - let fid = hub.render_pipelines.prepare(device_id.backend(), id_in); + let fid = hub.render_pipelines.prepare(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); let error = 'error: { @@ -1297,10 +1216,7 @@ impl Global { break 'error pipeline::ImplicitLayoutError::MissingImplicitPipelineIds.into(); } - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -1313,37 +1229,30 @@ impl Global { let layout = desc .layout - .map(|layout| { - hub.pipeline_layouts - .get(layout) - .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout) - }) + .map(|layout| hub.pipeline_layouts.get(layout).get()) .transpose(); let layout = match layout { Ok(layout) => layout, - Err(e) => break 'error e, + Err(e) => break 'error e.into(), }; let cache = desc .cache - .map(|cache| { - hub.pipeline_caches - .get(cache) - .map_err(|_| pipeline::CreateRenderPipelineError::InvalidCache) - }) + .map(|cache| hub.pipeline_caches.get(cache).get()) .transpose(); let cache = match cache { Ok(cache) => cache, - Err(e) => break 'error e, + Err(e) => break 'error e.into(), }; let vertex = { let module = hub .shader_modules .get(desc.vertex.stage.module) - .map_err(|_| pipeline::CreateRenderPipelineError::Stage { + .get() + .map_err(|e| pipeline::CreateRenderPipelineError::Stage { stage: wgt::ShaderStages::VERTEX, - error: crate::validation::StageError::InvalidModule, + error: e.into(), }); let module = match module { Ok(module) => module, @@ -1365,12 +1274,14 @@ impl Global { }; let fragment = if let Some(ref state) = desc.fragment { - let module = hub.shader_modules.get(state.stage.module).map_err(|_| { - pipeline::CreateRenderPipelineError::Stage { + let module = hub + .shader_modules + .get(state.stage.module) + .get() + .map_err(|e| pipeline::CreateRenderPipelineError::Stage { stage: wgt::ShaderStages::FRAGMENT, - error: crate::validation::StageError::InvalidModule, - } - }); + error: e.into(), + }); let module = match module { Ok(module) => module, Err(e) => break 'error e, @@ -1424,7 +1335,7 @@ impl Global { let mut pipeline_layout_guard = hub.pipeline_layouts.write(); let mut bgl_guard = hub.bind_group_layouts.write(); - pipeline_layout_guard.insert(ids.root_id, pipeline.layout.clone()); + pipeline_layout_guard.insert(ids.root_id, Fallible::Valid(pipeline.layout.clone())); let mut group_ids = ids.group_ids.iter(); // NOTE: If the first iterator is longer than the second, the `.zip()` impl will still advance the // the first iterator before realizing that the second iterator has finished. @@ -1436,29 +1347,29 @@ impl Global { .iter() .zip(&mut group_ids) { - bgl_guard.insert(*bgl_id, bgl.clone()); + bgl_guard.insert(*bgl_id, Fallible::Valid(bgl.clone())); } for bgl_id in group_ids { - bgl_guard.insert_error(*bgl_id); + bgl_guard.insert(*bgl_id, Fallible::Invalid(Arc::new(String::new()))); } } - let id = fid.assign(pipeline); + let id = fid.assign(Fallible::Valid(pipeline)); api_log!("Device::create_render_pipeline -> {id:?}"); return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); // We also need to assign errors to the implicit pipeline layout and the // implicit bind group layouts. if let Some(ids) = implicit_context { let mut pipeline_layout_guard = hub.pipeline_layouts.write(); let mut bgl_guard = hub.bind_group_layouts.write(); - pipeline_layout_guard.insert_error(ids.root_id); + pipeline_layout_guard.insert(ids.root_id, Fallible::Invalid(Arc::new(String::new()))); for bgl_id in ids.group_ids { - bgl_guard.insert_error(bgl_id); + bgl_guard.insert(bgl_id, Fallible::Invalid(Arc::new(String::new()))); } } @@ -1480,16 +1391,15 @@ impl Global { ) { let hub = &self.hub; + let fid = hub.bind_group_layouts.prepare(id_in); + let error = 'error: { - let pipeline = match hub.render_pipelines.get(pipeline_id) { + let pipeline = match hub.render_pipelines.get(pipeline_id).get() { Ok(pipeline) => pipeline, - Err(_) => break 'error binding_model::GetBindGroupLayoutError::InvalidPipeline, + Err(e) => break 'error e.into(), }; let id = match pipeline.layout.bind_group_layouts.get(index as usize) { - Some(bg) => hub - .bind_group_layouts - .prepare(pipeline_id.backend(), id_in) - .assign(bg.clone()), + Some(bg) => fid.assign(Fallible::Valid(bg.clone())), None => { break 'error binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index) } @@ -1497,10 +1407,7 @@ impl Global { return (id, None); }; - let id = hub - .bind_group_layouts - .prepare(pipeline_id.backend(), id_in) - .assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(String::new()))); (id, Some(error)) } @@ -1510,9 +1417,11 @@ impl Global { let hub = &self.hub; - if let Some(_pipeline) = hub.render_pipelines.unregister(render_pipeline_id) { - #[cfg(feature = "trace")] - if let Some(t) = _pipeline.device.trace.lock().as_mut() { + let _pipeline = hub.render_pipelines.remove(render_pipeline_id); + + #[cfg(feature = "trace")] + if let Ok(pipeline) = _pipeline.get() { + if let Some(t) = pipeline.device.trace.lock().as_mut() { t.add(trace::Action::DestroyRenderPipeline(render_pipeline_id)); } } @@ -1535,7 +1444,7 @@ impl Global { let missing_implicit_pipeline_ids = desc.layout.is_none() && id_in.is_some() && implicit_pipeline_ids.is_none(); - let fid = hub.compute_pipelines.prepare(device_id.backend(), id_in); + let fid = hub.compute_pipelines.prepare(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); let error = 'error: { @@ -1544,10 +1453,7 @@ impl Global { break 'error pipeline::ImplicitLayoutError::MissingImplicitPipelineIds.into(); } - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -1560,34 +1466,23 @@ impl Global { let layout = desc .layout - .map(|layout| { - hub.pipeline_layouts - .get(layout) - .map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout) - }) + .map(|layout| hub.pipeline_layouts.get(layout).get()) .transpose(); let layout = match layout { Ok(layout) => layout, - Err(e) => break 'error e, + Err(e) => break 'error e.into(), }; let cache = desc .cache - .map(|cache| { - hub.pipeline_caches - .get(cache) - .map_err(|_| pipeline::CreateComputePipelineError::InvalidCache) - }) + .map(|cache| hub.pipeline_caches.get(cache).get()) .transpose(); let cache = match cache { Ok(cache) => cache, - Err(e) => break 'error e, + Err(e) => break 'error e.into(), }; - let module = hub - .shader_modules - .get(desc.stage.module) - .map_err(|_| crate::validation::StageError::InvalidModule); + let module = hub.shader_modules.get(desc.stage.module).get(); let module = match module { Ok(module) => module, Err(e) => break 'error e.into(), @@ -1626,7 +1521,7 @@ impl Global { let mut pipeline_layout_guard = hub.pipeline_layouts.write(); let mut bgl_guard = hub.bind_group_layouts.write(); - pipeline_layout_guard.insert(ids.root_id, pipeline.layout.clone()); + pipeline_layout_guard.insert(ids.root_id, Fallible::Valid(pipeline.layout.clone())); let mut group_ids = ids.group_ids.iter(); // NOTE: If the first iterator is longer than the second, the `.zip()` impl will still advance the // the first iterator before realizing that the second iterator has finished. @@ -1638,29 +1533,29 @@ impl Global { .iter() .zip(&mut group_ids) { - bgl_guard.insert(*bgl_id, bgl.clone()); + bgl_guard.insert(*bgl_id, Fallible::Valid(bgl.clone())); } for bgl_id in group_ids { - bgl_guard.insert_error(*bgl_id); + bgl_guard.insert(*bgl_id, Fallible::Invalid(Arc::new(String::new()))); } } - let id = fid.assign(pipeline); + let id = fid.assign(Fallible::Valid(pipeline)); api_log!("Device::create_compute_pipeline -> {id:?}"); return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); // We also need to assign errors to the implicit pipeline layout and the // implicit bind group layouts. if let Some(ids) = implicit_context { let mut pipeline_layout_guard = hub.pipeline_layouts.write(); let mut bgl_guard = hub.bind_group_layouts.write(); - pipeline_layout_guard.insert_error(ids.root_id); + pipeline_layout_guard.insert(ids.root_id, Fallible::Invalid(Arc::new(String::new()))); for bgl_id in ids.group_ids { - bgl_guard.insert_error(bgl_id); + bgl_guard.insert(bgl_id, Fallible::Invalid(Arc::new(String::new()))); } } @@ -1680,17 +1575,16 @@ impl Global { ) { let hub = &self.hub; + let fid = hub.bind_group_layouts.prepare(id_in); + let error = 'error: { - let pipeline = match hub.compute_pipelines.get(pipeline_id) { + let pipeline = match hub.compute_pipelines.get(pipeline_id).get() { Ok(pipeline) => pipeline, - Err(_) => break 'error binding_model::GetBindGroupLayoutError::InvalidPipeline, + Err(e) => break 'error e.into(), }; let id = match pipeline.layout.bind_group_layouts.get(index as usize) { - Some(bg) => hub - .bind_group_layouts - .prepare(pipeline_id.backend(), id_in) - .assign(bg.clone()), + Some(bg) => fid.assign(Fallible::Valid(bg.clone())), None => { break 'error binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index) } @@ -1699,10 +1593,7 @@ impl Global { return (id, None); }; - let id = hub - .bind_group_layouts - .prepare(pipeline_id.backend(), id_in) - .assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(String::new()))); (id, Some(error)) } @@ -1712,9 +1603,11 @@ impl Global { let hub = &self.hub; - if let Some(_pipeline) = hub.compute_pipelines.unregister(compute_pipeline_id) { - #[cfg(feature = "trace")] - if let Some(t) = _pipeline.device.trace.lock().as_mut() { + let _pipeline = hub.compute_pipelines.remove(compute_pipeline_id); + + #[cfg(feature = "trace")] + if let Ok(pipeline) = _pipeline.get() { + if let Some(t) = pipeline.device.trace.lock().as_mut() { t.add(trace::Action::DestroyComputePipeline(compute_pipeline_id)); } } @@ -1736,13 +1629,9 @@ impl Global { let hub = &self.hub; - let fid = hub.pipeline_caches.prepare(device_id.backend(), id_in); + let fid = hub.pipeline_caches.prepare(id_in); let error: pipeline::CreatePipelineCacheError = 'error: { - let device = match hub.devices.get(device_id) { - Ok(device) => device, - // TODO: Handle error properly - Err(crate::storage::InvalidId) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -1755,7 +1644,7 @@ impl Global { let cache = unsafe { device.create_pipeline_cache(desc) }; match cache { Ok(cache) => { - let id = fid.assign(cache); + let id = fid.assign(Fallible::Valid(cache)); api_log!("Device::create_pipeline_cache -> {id:?}"); return (id, None); } @@ -1763,7 +1652,7 @@ impl Global { } }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); (id, Some(error)) } @@ -1774,12 +1663,13 @@ impl Global { let hub = &self.hub; - if let Some(cache) = hub.pipeline_caches.unregister(pipeline_cache_id) { - #[cfg(feature = "trace")] + let _cache = hub.pipeline_caches.remove(pipeline_cache_id); + + #[cfg(feature = "trace")] + if let Ok(cache) = _cache.get() { if let Some(t) = cache.device.trace.lock().as_mut() { t.add(trace::Action::DestroyPipelineCache(pipeline_cache_id)); } - drop(cache) } } @@ -1910,13 +1800,7 @@ impl Global { // User callbacks must not be called while we are holding locks. let user_callbacks; { - let hub = &self.hub; - let surface_guard = self.surfaces.read(); - - let device = match hub.devices.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -1927,10 +1811,7 @@ impl Global { break 'error e.into(); } - let surface = match surface_guard.get(surface_id) { - Ok(surface) => surface, - Err(_) => break 'error E::InvalidSurface, - }; + let surface = self.surfaces.get(surface_id); let caps = match surface.get_capabilities(&device.adapter) { Ok(caps) => caps, @@ -2013,7 +1894,7 @@ impl Global { // // https://github.com/gfx-rs/wgpu/issues/4105 - let surface_raw = surface.raw(device_id.backend()).unwrap(); + let surface_raw = surface.raw(device.backend()).unwrap(); match unsafe { surface_raw.configure(device.raw(), &hal_config) } { Ok(()) => (), Err(error) => { @@ -2021,7 +1902,9 @@ impl Global { hal::SurfaceError::Outdated | hal::SurfaceError::Lost => { E::InvalidSurface } - hal::SurfaceError::Device(error) => E::Device(error.into()), + hal::SurfaceError::Device(error) => { + E::Device(device.handle_hal_error(error)) + } hal::SurfaceError::Other(message) => { log::error!("surface configuration failed: {}", message); E::InvalidSurface @@ -2055,11 +1938,7 @@ impl Global { ) -> Result { api_log!("Device::poll {maintain:?}"); - let hub = &self.hub; - let device = hub - .devices - .get(device_id) - .map_err(|_| DeviceError::InvalidDeviceId)?; + let device = self.hub.devices.get(device_id); let DevicePoll { closures, @@ -2097,7 +1976,6 @@ impl Global { /// submissions still in flight. fn poll_all_devices_of_api( &self, - backend: wgt::Backend, force_wait: bool, closures: &mut UserClosures, ) -> Result { @@ -2108,7 +1986,7 @@ impl Global { { let device_guard = hub.devices.read(); - for (_id, device) in device_guard.iter(backend) { + for (_id, device) in device_guard.iter() { let maintain = if force_wait { wgt::Maintain::Wait } else { @@ -2138,66 +2016,33 @@ impl Global { pub fn poll_all_devices(&self, force_wait: bool) -> Result { api_log!("poll_all_devices"); let mut closures = UserClosures::default(); - let mut all_queue_empty = true; - - #[cfg(vulkan)] - { - all_queue_empty &= - self.poll_all_devices_of_api(wgt::Backend::Vulkan, force_wait, &mut closures)?; - } - #[cfg(metal)] - { - all_queue_empty &= - self.poll_all_devices_of_api(wgt::Backend::Metal, force_wait, &mut closures)?; - } - #[cfg(dx12)] - { - all_queue_empty &= - self.poll_all_devices_of_api(wgt::Backend::Dx12, force_wait, &mut closures)?; - } - #[cfg(gles)] - { - all_queue_empty &= - self.poll_all_devices_of_api(wgt::Backend::Gl, force_wait, &mut closures)?; - } + let all_queue_empty = self.poll_all_devices_of_api(force_wait, &mut closures)?; closures.fire(); Ok(all_queue_empty) } - pub fn device_start_capture(&self, id: DeviceId) { + pub fn device_start_capture(&self, device_id: DeviceId) { api_log!("Device::start_capture"); - let hub = &self.hub; + let device = self.hub.devices.get(device_id); - if let Ok(device) = hub.devices.get(id) { - if !device.is_valid() { - return; - } - unsafe { device.raw().start_capture() }; + if !device.is_valid() { + return; } + unsafe { device.raw().start_capture() }; } - pub fn device_stop_capture(&self, id: DeviceId) { + pub fn device_stop_capture(&self, device_id: DeviceId) { api_log!("Device::stop_capture"); - let hub = &self.hub; + let device = self.hub.devices.get(device_id); - if let Ok(device) = hub.devices.get(id) { - if !device.is_valid() { - return; - } - unsafe { device.raw().stop_capture() }; + if !device.is_valid() { + return; } - } - - // This is a test-only function to force the device into an - // invalid state by inserting an error value in its place in - // the registry. - pub fn device_make_invalid(&self, device_id: DeviceId) { - let hub = &self.hub; - hub.devices.force_replace_with_error(device_id); + unsafe { device.raw().stop_capture() }; } pub fn pipeline_cache_get_data(&self, id: id::PipelineCacheId) -> Option> { @@ -2205,7 +2050,7 @@ impl Global { api_log!("PipelineCache::get_data"); let hub = &self.hub; - if let Ok(cache) = hub.pipeline_caches.get(id) { + if let Ok(cache) = hub.pipeline_caches.get(id).get() { // TODO: Is this check needed? if !cache.device.is_valid() { return None; @@ -2233,22 +2078,20 @@ impl Global { profiling::scope!("Device::drop"); api_log!("Device::drop {device_id:?}"); - let hub = &self.hub; - if let Some(device) = hub.devices.unregister(device_id) { - let device_lost_closure = device.lock_life().device_lost_closure.take(); - if let Some(closure) = device_lost_closure { - closure.call(DeviceLostReason::Dropped, String::from("Device dropped.")); - } + let device = self.hub.devices.remove(device_id); + let device_lost_closure = device.lock_life().device_lost_closure.take(); + if let Some(closure) = device_lost_closure { + closure.call(DeviceLostReason::Dropped, String::from("Device dropped.")); + } - // The things `Device::prepare_to_die` takes care are mostly - // unnecessary here. We know our queue is empty, so we don't - // need to wait for submissions or triage them. We know we were - // just polled, so `life_tracker.free_resources` is empty. - debug_assert!(device.lock_life().queue_empty()); - device.pending_writes.lock().deactivate(); + // The things `Device::prepare_to_die` takes care are mostly + // unnecessary here. We know our queue is empty, so we don't + // need to wait for submissions or triage them. We know we were + // just polled, so `life_tracker.free_resources` is empty. + debug_assert!(device.lock_life().queue_empty()); + device.pending_writes.lock().deactivate(); - drop(device); - } + drop(device); } // This closure will be called exactly once during "lose the device", @@ -2258,71 +2101,47 @@ impl Global { device_id: DeviceId, device_lost_closure: DeviceLostClosure, ) { - let hub = &self.hub; - - if let Ok(device) = hub.devices.get(device_id) { - let mut life_tracker = device.lock_life(); - if let Some(existing_closure) = life_tracker.device_lost_closure.take() { - // It's important to not hold the lock while calling the closure. - drop(life_tracker); - existing_closure.call(DeviceLostReason::ReplacedCallback, "".to_string()); - life_tracker = device.lock_life(); - } - life_tracker.device_lost_closure = Some(device_lost_closure); - } else { - // No device? Okay. Just like we have to call any existing closure - // before we drop it, we need to call this closure before we exit - // this function, because there's no device that is ever going to - // call it. - device_lost_closure.call(DeviceLostReason::DeviceInvalid, "".to_string()); + let device = self.hub.devices.get(device_id); + + let mut life_tracker = device.lock_life(); + if let Some(existing_closure) = life_tracker.device_lost_closure.take() { + // It's important to not hold the lock while calling the closure. + drop(life_tracker); + existing_closure.call(DeviceLostReason::ReplacedCallback, "".to_string()); + life_tracker = device.lock_life(); } + life_tracker.device_lost_closure = Some(device_lost_closure); } pub fn device_destroy(&self, device_id: DeviceId) { api_log!("Device::destroy {device_id:?}"); - let hub = &self.hub; - - if let Ok(device) = hub.devices.get(device_id) { - // Follow the steps at - // https://gpuweb.github.io/gpuweb/#dom-gpudevice-destroy. - // It's legal to call destroy multiple times, but if the device - // is already invalid, there's nothing more to do. There's also - // no need to return an error. - if !device.is_valid() { - return; - } + let device = self.hub.devices.get(device_id); - // The last part of destroy is to lose the device. The spec says - // delay that until all "currently-enqueued operations on any - // queue on this device are completed." This is accomplished by - // setting valid to false, and then relying upon maintain to - // check for empty queues and a DeviceLostClosure. At that time, - // the DeviceLostClosure will be called with "destroyed" as the - // reason. - device.valid.store(false, Ordering::Relaxed); + // Follow the steps at + // https://gpuweb.github.io/gpuweb/#dom-gpudevice-destroy. + // It's legal to call destroy multiple times, but if the device + // is already invalid, there's nothing more to do. There's also + // no need to return an error. + if !device.is_valid() { + return; } - } - - pub fn device_mark_lost(&self, device_id: DeviceId, message: &str) { - api_log!("Device::mark_lost {device_id:?}"); - let hub = &self.hub; - - if let Ok(device) = hub.devices.get(device_id) { - device.lose(message); - } + // The last part of destroy is to lose the device. The spec says + // delay that until all "currently-enqueued operations on any + // queue on this device are completed." This is accomplished by + // setting valid to false, and then relying upon maintain to + // check for empty queues and a DeviceLostClosure. At that time, + // the DeviceLostClosure will be called with "destroyed" as the + // reason. + device.valid.store(false, Ordering::Release); } pub fn device_get_internal_counters(&self, device_id: DeviceId) -> wgt::InternalCounters { - let hub = &self.hub; - if let Ok(device) = hub.devices.get(device_id) { - wgt::InternalCounters { - hal: device.get_hal_counters(), - core: wgt::CoreCounters {}, - } - } else { - Default::default() + let device = self.hub.devices.get(device_id); + wgt::InternalCounters { + hal: device.get_hal_counters(), + core: wgt::CoreCounters {}, } } @@ -2330,21 +2149,15 @@ impl Global { &self, device_id: DeviceId, ) -> Option { - let hub = &self.hub; - hub.devices - .get(device_id) - .ok() - .and_then(|device| device.generate_allocator_report()) + let device = self.hub.devices.get(device_id); + device.generate_allocator_report() } pub fn queue_drop(&self, queue_id: QueueId) { profiling::scope!("Queue::drop"); api_log!("Queue::drop {queue_id:?}"); - let hub = &self.hub; - if let Some(queue) = hub.queues.unregister(queue_id) { - drop(queue); - } + self.hub.queues.remove(queue_id); } pub fn buffer_map_async( @@ -2360,9 +2173,9 @@ impl Global { let hub = &self.hub; let op_and_err = 'error: { - let buffer = match hub.buffers.get(buffer_id) { + let buffer = match hub.buffers.get(buffer_id).get() { Ok(buffer) => buffer, - Err(_) => break 'error Some((op, BufferAccessError::InvalidBufferId(buffer_id))), + Err(e) => break 'error Some((op, e.into())), }; buffer.map_async(offset, size, op).err() @@ -2393,10 +2206,7 @@ impl Global { let hub = &self.hub; - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| BufferAccessError::InvalidBufferId(buffer_id))?; + let buffer = hub.buffers.get(buffer_id).get()?; { let snatch_guard = buffer.device.snatchable_lock.read(); @@ -2469,10 +2279,7 @@ impl Global { let hub = &self.hub; - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| BufferAccessError::InvalidBufferId(buffer_id))?; + let buffer = hub.buffers.get(buffer_id).get()?; let snatch_guard = buffer.device.snatchable_lock.read(); buffer.check_destroyed(&snatch_guard)?; diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index c89f04d74b..92c022351f 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -309,7 +309,7 @@ fn map_buffer( let raw_buffer = buffer.try_raw(snatch_guard)?; let mapping = unsafe { raw.map_buffer(raw_buffer, offset..offset + size) - .map_err(DeviceError::from)? + .map_err(|e| buffer.device.handle_hal_error(e))? }; if !mapping.is_coherent && kind == HostMap::Read { @@ -337,19 +337,41 @@ fn map_buffer( let mapped = unsafe { std::slice::from_raw_parts_mut(mapping.ptr.as_ptr(), size as usize) }; - for uninitialized in buffer - .initialization_status - .write() - .drain(offset..(size + offset)) + // We can't call flush_mapped_ranges in this case, so we can't drain the uninitialized ranges either + if !mapping.is_coherent + && kind == HostMap::Read + && !buffer.usage.contains(wgt::BufferUsages::MAP_WRITE) { - // The mapping's pointer is already offset, however we track the - // uninitialized range relative to the buffer's start. - let fill_range = - (uninitialized.start - offset) as usize..(uninitialized.end - offset) as usize; - mapped[fill_range].fill(0); - - if !mapping.is_coherent && kind == HostMap::Read { - unsafe { raw.flush_mapped_ranges(raw_buffer, &[uninitialized]) }; + for uninitialized in buffer + .initialization_status + .write() + .uninitialized(offset..(size + offset)) + { + // The mapping's pointer is already offset, however we track the + // uninitialized range relative to the buffer's start. + let fill_range = + (uninitialized.start - offset) as usize..(uninitialized.end - offset) as usize; + mapped[fill_range].fill(0); + } + } else { + for uninitialized in buffer + .initialization_status + .write() + .drain(offset..(size + offset)) + { + // The mapping's pointer is already offset, however we track the + // uninitialized range relative to the buffer's start. + let fill_range = + (uninitialized.start - offset) as usize..(uninitialized.end - offset) as usize; + mapped[fill_range].fill(0); + + // NOTE: This is only possible when MAPPABLE_PRIMARY_BUFFERS is enabled. + if !mapping.is_coherent + && kind == HostMap::Read + && buffer.usage.contains(wgt::BufferUsages::MAP_WRITE) + { + unsafe { raw.flush_mapped_ranges(raw_buffer, &[uninitialized]) }; + } } } @@ -393,18 +415,20 @@ pub enum DeviceError { OutOfMemory, #[error("Creation of a resource failed for a reason other than running out of memory.")] ResourceCreationFailed, - #[error("DeviceId is invalid")] - InvalidDeviceId, #[error(transparent)] DeviceMismatch(#[from] Box), } -impl From for DeviceError { - fn from(error: hal::DeviceError) -> Self { +impl DeviceError { + /// Only use this function in contexts where there is no `Device`. + /// + /// Use [`Device::handle_hal_error`] otherwise. + pub fn from_hal(error: hal::DeviceError) -> Self { match error { - hal::DeviceError::Lost => DeviceError::Lost, - hal::DeviceError::OutOfMemory => DeviceError::OutOfMemory, - hal::DeviceError::ResourceCreationFailed => DeviceError::ResourceCreationFailed, + hal::DeviceError::Lost => Self::Lost, + hal::DeviceError::OutOfMemory => Self::OutOfMemory, + hal::DeviceError::ResourceCreationFailed => Self::ResourceCreationFailed, + hal::DeviceError::Unexpected => Self::Lost, } } } @@ -434,20 +458,12 @@ pub struct ImplicitPipelineIds<'a> { impl ImplicitPipelineIds<'_> { fn prepare(self, hub: &Hub) -> ImplicitPipelineContext { - let backend = self.root_id.backend(); ImplicitPipelineContext { - root_id: hub - .pipeline_layouts - .prepare(backend, Some(self.root_id)) - .into_id(), + root_id: hub.pipeline_layouts.prepare(Some(self.root_id)).id(), group_ids: self .group_ids .iter() - .map(|id_in| { - hub.bind_group_layouts - .prepare(backend, Some(*id_in)) - .into_id() - }) + .map(|id_in| hub.bind_group_layouts.prepare(Some(*id_in)).id()) .collect(), } } diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index c4c6335d7a..c17aaf380f 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -4,7 +4,8 @@ use crate::{ api_log, command::{ extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range, - ClearError, CommandAllocator, CommandBuffer, CopySide, ImageCopyTexture, TransferError, + ClearError, CommandAllocator, CommandBuffer, CommandEncoderError, CopySide, + ImageCopyTexture, TransferError, }, conv, device::{DeviceError, WaitIdleError}, @@ -16,8 +17,8 @@ use crate::{ lock::RwLockWriteGuard, resource::{ Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedResourceError, - DestroyedTexture, FlushedStagingBuffer, Labeled, ParentDevice, ResourceErrorIdent, - StagingBuffer, Texture, TextureInner, Trackable, + DestroyedTexture, FlushedStagingBuffer, InvalidResourceError, Labeled, ParentDevice, + ResourceErrorIdent, StagingBuffer, Texture, TextureInner, Trackable, }, resource_log, track::{self, Tracker, TrackerIndex}, @@ -273,17 +274,20 @@ impl PendingWrites { fn pre_submit( &mut self, command_allocator: &CommandAllocator, - device: &dyn hal::DynDevice, - queue: &dyn hal::DynQueue, + device: &Device, + queue: &Queue, ) -> Result, DeviceError> { if self.is_recording { let pending_buffers = mem::take(&mut self.dst_buffers); let pending_textures = mem::take(&mut self.dst_textures); - let cmd_buf = unsafe { self.command_encoder.end_encoding()? }; + let cmd_buf = unsafe { self.command_encoder.end_encoding() } + .map_err(|e| device.handle_hal_error(e))?; self.is_recording = false; - let new_encoder = command_allocator.acquire_encoder(device, queue)?; + let new_encoder = command_allocator + .acquire_encoder(device.raw(), queue.raw()) + .map_err(|e| device.handle_hal_error(e))?; let encoder = EncoderInFlight { raw: mem::replace(&mut self.command_encoder, new_encoder), @@ -322,15 +326,9 @@ impl PendingWrites { } } -#[derive(Clone, Debug, Error)] -#[error("Queue is invalid")] -pub struct InvalidQueue; - #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum QueueWriteError { - #[error("QueueId is invalid")] - InvalidQueueId, #[error(transparent)] Queue(#[from] DeviceError), #[error(transparent)] @@ -339,13 +337,13 @@ pub enum QueueWriteError { MemoryInitFailure(#[from] ClearError), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum QueueSubmitError { - #[error("QueueId is invalid")] - InvalidQueueId, #[error(transparent)] Queue(#[from] DeviceError), #[error(transparent)] @@ -361,6 +359,10 @@ pub enum QueueSubmitError { #[error("GPU got stuck :(")] StuckGpu, #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), + #[error(transparent)] + CommandEncoder(#[from] CommandEncoderError), + #[error(transparent)] ValidateBlasActionsError(#[from] crate::ray_tracing::ValidateBlasActionsError), #[error(transparent)] ValidateTlasActionsError(#[from] crate::ray_tracing::ValidateTlasActionsError), @@ -381,15 +383,9 @@ impl Global { let hub = &self.hub; - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| TransferError::InvalidBufferId(buffer_id))?; + let buffer = hub.buffers.get(buffer_id).get()?; - let queue = hub - .queues - .get(queue_id) - .map_err(|_| QueueWriteError::InvalidQueueId)?; + let queue = hub.queues.get(queue_id); let device = &queue.device; @@ -449,18 +445,15 @@ impl Global { profiling::scope!("Queue::create_staging_buffer"); let hub = &self.hub; - let queue = hub - .queues - .get(queue_id) - .map_err(|_| QueueWriteError::InvalidQueueId)?; + let queue = hub.queues.get(queue_id); let device = &queue.device; let staging_buffer = StagingBuffer::new(device, buffer_size)?; let ptr = unsafe { staging_buffer.ptr() }; - let fid = hub.staging_buffers.prepare(queue_id.backend(), id_in); - let id = fid.assign(Arc::new(staging_buffer)); + let fid = hub.staging_buffers.prepare(id_in); + let id = fid.assign(staging_buffer); resource_log!("Queue::create_staging_buffer {id:?}"); Ok((id, ptr)) @@ -476,18 +469,11 @@ impl Global { profiling::scope!("Queue::write_staging_buffer"); let hub = &self.hub; - let queue = hub - .queues - .get(queue_id) - .map_err(|_| QueueWriteError::InvalidQueueId)?; + let queue = hub.queues.get(queue_id); let device = &queue.device; - let staging_buffer = hub - .staging_buffers - .unregister(staging_buffer_id) - .and_then(Arc::into_inner) - .ok_or_else(|| QueueWriteError::Transfer(TransferError::InvalidBufferId(buffer_id)))?; + let staging_buffer = hub.staging_buffers.remove(staging_buffer_id); let mut pending_writes = device.pending_writes.lock(); @@ -520,10 +506,7 @@ impl Global { profiling::scope!("Queue::validate_write_buffer"); let hub = &self.hub; - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| TransferError::InvalidBufferId(buffer_id))?; + let buffer = hub.buffers.get(buffer_id).get()?; self.queue_validate_write_buffer_impl(&buffer, buffer_offset, buffer_size)?; @@ -566,10 +549,7 @@ impl Global { ) -> Result<(), QueueWriteError> { let hub = &self.hub; - let dst = hub - .buffers - .get(buffer_id) - .map_err(|_| TransferError::InvalidBufferId(buffer_id))?; + let dst = hub.buffers.get(buffer_id).get()?; let transition = { let mut trackers = device.trackers.lock(); @@ -626,10 +606,7 @@ impl Global { let hub = &self.hub; - let queue = hub - .queues - .get(queue_id) - .map_err(|_| QueueWriteError::InvalidQueueId)?; + let queue = hub.queues.get(queue_id); let device = &queue.device; @@ -649,10 +626,7 @@ impl Global { return Ok(()); } - let dst = hub - .textures - .get(destination.texture) - .map_err(|_| TransferError::InvalidTextureId(destination.texture))?; + let dst = hub.textures.get(destination.texture).get()?; dst.same_device_as(queue.as_ref())?; @@ -743,12 +717,6 @@ impl Global { let snatch_guard = device.snatchable_lock.read(); - // Re-get `dst` immutably here, so that the mutable borrow of the - // `texture_guard.get` above ends in time for the `clear_texture` - // call above. Since we've held `texture_guard` the whole time, we know - // the texture hasn't gone away in the mean time, so we can unwrap. - let dst = hub.textures.get(destination.texture).unwrap(); - let dst_raw = dst.try_raw(&snatch_guard)?; let (block_width, block_height) = dst.desc.format.block_dimensions(); @@ -867,10 +835,7 @@ impl Global { let hub = &self.hub; - let queue = hub - .queues - .get(queue_id) - .map_err(|_| QueueWriteError::InvalidQueueId)?; + let queue = hub.queues.get(queue_id); let device = &queue.device; @@ -898,7 +863,7 @@ impl Global { let src_width = source.source.width(); let src_height = source.source.height(); - let dst = hub.textures.get(destination.texture).unwrap(); + let dst = hub.textures.get(destination.texture).get()?; if !conv::is_valid_external_image_copy_dst_texture_format(dst.desc.format) { return Err( @@ -1077,10 +1042,7 @@ impl Global { let (submit_index, callbacks) = { let hub = &self.hub; - let queue = hub - .queues - .get(queue_id) - .map_err(|_| QueueSubmitError::InvalidQueueId)?; + let queue = hub.queues.get(queue_id); let device = &queue.device; @@ -1101,116 +1063,77 @@ impl Global { let mut submit_surface_textures_owned = FastHashMap::default(); { - let mut command_buffer_guard = hub.command_buffers.write(); + let command_buffer_guard = hub.command_buffers.read(); if !command_buffer_ids.is_empty() { profiling::scope!("prepare"); + let mut first_error = None; + //TODO: if multiple command buffers are submitted, we can re-use the last // native command buffer of the previous chain instead of always creating // a temporary one, since the chains are not finished. // finish all the command buffers first - for &cmb_id in command_buffer_ids { + for command_buffer_id in command_buffer_ids { profiling::scope!("process command buffer"); // we reset the used surface textures every time we use // it, so make sure to set_size on it. used_surface_textures.set_size(device.tracker_indices.textures.size()); + let command_buffer = command_buffer_guard.get(*command_buffer_id); + + // Note that we are required to invalidate all command buffers in both the success and failure paths. + // This is why we `continue` and don't early return via `?`. #[allow(unused_mut)] - let mut cmdbuf = match command_buffer_guard.replace_with_error(cmb_id) { - Ok(cmdbuf) => cmdbuf, - Err(_) => continue, - }; + let mut cmd_buf_data = command_buffer.try_take(); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { - trace.add(Action::Submit( - submit_index, - cmdbuf - .data - .lock() - .as_mut() - .unwrap() - .commands - .take() - .unwrap(), - )); - } - - cmdbuf.same_device_as(queue.as_ref())?; - - if !cmdbuf.is_finished() { - let cmdbuf = Arc::into_inner(cmdbuf).expect( - "Command buffer cannot be destroyed because is still in use", - ); - device.destroy_command_buffer(cmdbuf); - continue; + if let Ok(ref mut cmd_buf_data) = cmd_buf_data { + trace.add(Action::Submit( + submit_index, + cmd_buf_data.commands.take().unwrap(), + )); + } } - { - profiling::scope!("check resource state"); - - let cmd_buf_data = cmdbuf.data.lock(); - let cmd_buf_trackers = &cmd_buf_data.as_ref().unwrap().trackers; - - // update submission IDs - { - profiling::scope!("buffers"); - for buffer in cmd_buf_trackers.buffers.used_resources() { - buffer.check_destroyed(&snatch_guard)?; - - match *buffer.map_state.lock() { - BufferMapState::Idle => (), - _ => { - return Err(QueueSubmitError::BufferStillMapped( - buffer.error_ident(), - )) - } - } + let mut baked = match cmd_buf_data { + Ok(cmd_buf_data) => { + let res = validate_command_buffer( + &command_buffer, + &queue, + &cmd_buf_data, + &snatch_guard, + &mut submit_surface_textures_owned, + &mut used_surface_textures, + ); + if let Err(err) = res { + first_error.get_or_insert(err); + cmd_buf_data.destroy(&command_buffer.device); + continue; } + cmd_buf_data.into_baked_commands() } - { - profiling::scope!("textures"); - for texture in cmd_buf_trackers.textures.used_resources() { - let should_extend = match texture.try_inner(&snatch_guard)? { - TextureInner::Native { .. } => false, - TextureInner::Surface { .. } => { - // Compare the Arcs by pointer as Textures don't implement Eq. - submit_surface_textures_owned - .insert(Arc::as_ptr(&texture), texture.clone()); - - true - } - }; - if should_extend { - unsafe { - used_surface_textures - .merge_single( - &texture, - None, - hal::TextureUses::PRESENT, - ) - .unwrap(); - }; - } - } + Err(err) => { + first_error.get_or_insert(err.into()); + continue; } - } + }; - let mut baked = cmdbuf.from_arc_into_baked(); + if first_error.is_some() { + continue; + } // execute resource transitions unsafe { - baked - .encoder - .begin_encoding(hal_label( - Some("(wgpu internal) Transit"), - device.instance_flags, - )) - .map_err(DeviceError::from)? - }; + baked.encoder.begin_encoding(hal_label( + Some("(wgpu internal) Transit"), + device.instance_flags, + )) + } + .map_err(|e| device.handle_hal_error(e))?; //Note: locking the trackers has to be done after the storages let mut trackers = device.trackers.lock(); @@ -1235,14 +1158,12 @@ impl Global { // but here we have a command encoder by hand, so it's easier to use it. if !used_surface_textures.is_empty() { unsafe { - baked - .encoder - .begin_encoding(hal_label( - Some("(wgpu internal) Present"), - device.instance_flags, - )) - .map_err(DeviceError::from)? - }; + baked.encoder.begin_encoding(hal_label( + Some("(wgpu internal) Present"), + device.instance_flags, + )) + } + .map_err(|e| device.handle_hal_error(e))?; let texture_barriers = trackers .textures .set_from_usage_scope_and_drain_transitions( @@ -1267,6 +1188,10 @@ impl Global { pending_textures: FastHashMap::default(), }); } + + if let Some(first_error) = first_error { + return Err(first_error); + } } } @@ -1310,7 +1235,7 @@ impl Global { } if let Some(pending_execution) = - pending_writes.pre_submit(&device.command_allocator, device.raw(), queue.raw())? + pending_writes.pre_submit(&device.command_allocator, device, &queue)? { active_executions.insert(0, pending_execution); } @@ -1335,15 +1260,13 @@ impl Global { } unsafe { - queue - .raw() - .submit( - &hal_command_buffers, - &submit_surface_textures, - (fence.as_mut(), submit_index), - ) - .map_err(DeviceError::from)?; + queue.raw().submit( + &hal_command_buffers, + &submit_surface_textures, + (fence.as_mut(), submit_index), + ) } + .map_err(|e| device.handle_hal_error(e))?; // Advance the successful submission index. device @@ -1383,27 +1306,71 @@ impl Global { Ok(submit_index) } - pub fn queue_get_timestamp_period(&self, queue_id: QueueId) -> Result { - let hub = &self.hub; - match hub.queues.get(queue_id) { - Ok(queue) => Ok(unsafe { queue.raw().get_timestamp_period() }), - Err(_) => Err(InvalidQueue), - } + pub fn queue_get_timestamp_period(&self, queue_id: QueueId) -> f32 { + let queue = self.hub.queues.get(queue_id); + unsafe { queue.raw().get_timestamp_period() } } pub fn queue_on_submitted_work_done( &self, queue_id: QueueId, closure: SubmittedWorkDoneClosure, - ) -> Result<(), InvalidQueue> { + ) { api_log!("Queue::on_submitted_work_done {queue_id:?}"); //TODO: flush pending writes - let hub = &self.hub; - match hub.queues.get(queue_id) { - Ok(queue) => queue.device.lock_life().add_work_done_closure(closure), - Err(_) => return Err(InvalidQueue), + let queue = self.hub.queues.get(queue_id); + queue.device.lock_life().add_work_done_closure(closure); + } +} + +fn validate_command_buffer( + command_buffer: &CommandBuffer, + queue: &Queue, + cmd_buf_data: &crate::command::CommandBufferMutable, + snatch_guard: &crate::snatch::SnatchGuard<'_>, + submit_surface_textures_owned: &mut FastHashMap<*const Texture, Arc>, + used_surface_textures: &mut track::TextureUsageScope, +) -> Result<(), QueueSubmitError> { + command_buffer.same_device_as(queue)?; + cmd_buf_data.check_finished()?; + + { + profiling::scope!("check resource state"); + + { + profiling::scope!("buffers"); + for buffer in cmd_buf_data.trackers.buffers.used_resources() { + buffer.check_destroyed(snatch_guard)?; + + match *buffer.map_state.lock() { + BufferMapState::Idle => (), + _ => return Err(QueueSubmitError::BufferStillMapped(buffer.error_ident())), + } + } + } + { + profiling::scope!("textures"); + for texture in cmd_buf_data.trackers.textures.used_resources() { + let should_extend = match texture.try_inner(snatch_guard)? { + TextureInner::Native { .. } => false, + TextureInner::Surface { .. } => { + // Compare the Arcs by pointer as Textures don't implement Eq. + submit_surface_textures_owned + .insert(Arc::as_ptr(&texture), texture.clone()); + + true + } + }; + if should_extend { + unsafe { + used_surface_textures + .merge_single(&texture, None, hal::TextureUses::PRESENT) + .unwrap(); + }; + } + } } - Ok(()) } + Ok(()) } diff --git a/wgpu-core/src/device/ray_tracing.rs b/wgpu-core/src/device/ray_tracing.rs index 3d1e102b6d..8b47e2553c 100644 --- a/wgpu-core/src/device/ray_tracing.rs +++ b/wgpu-core/src/device/ray_tracing.rs @@ -6,7 +6,7 @@ use hal::AccelerationStructureTriangleIndices; #[cfg(feature = "trace")] use crate::device::trace; use crate::lock::rank; -use crate::resource::TrackingData; +use crate::resource::{Fallible, TrackingData}; use crate::{ device::{queue::TempResource, Device, DeviceError}, global::Global, @@ -72,7 +72,7 @@ impl Device { format: hal::AccelerationStructureFormat::BottomLevel, }) } - .map_err(DeviceError::from)?; + .map_err(DeviceError::from_hal)?; let handle = unsafe { self.raw() @@ -120,7 +120,7 @@ impl Device { format: hal::AccelerationStructureFormat::TopLevel, }) } - .map_err(DeviceError::from)?; + .map_err(DeviceError::from_hal)?; let instance_buffer_size = get_raw_tlas_instance_size(self.backend()) * std::cmp::max(desc.max_instances, 1) as usize; @@ -133,7 +133,7 @@ impl Device { memory_flags: hal::MemoryFlags::PREFER_COHERENT, }) } - .map_err(DeviceError::from)?; + .map_err(DeviceError::from_hal)?; Ok(Arc::new(resource::Tlas { raw: ManuallyDrop::new(raw), @@ -162,17 +162,15 @@ impl Global { profiling::scope!("Device::create_blas"); let hub = &self.hub; - let fid = hub.blas_s.prepare(device_id.backend(), id_in); + let fid = hub.blas_s.prepare(id_in); let device_guard = hub.devices.read(); let error = 'error: { - let device = match device_guard.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), + let device = device_guard.get(device_id); + match device.check_is_valid() { + Ok(_) => {} + Err(err) => break 'error CreateBlasError::Device(err), }; - if !device.is_valid() { - break 'error DeviceError::Lost.into(); - } #[cfg(feature = "trace")] if let Some(trace) = device.trace.lock().as_mut() { @@ -189,13 +187,13 @@ impl Global { }; let handle = blas.handle; - let id = fid.assign(blas.clone()); + let id = fid.assign(Fallible::Valid(blas.clone())); log::info!("Created blas {:?} with {:?}", id, desc); return (id, Some(handle), None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(error.to_string()))); (id, None, Some(error)) } @@ -208,14 +206,15 @@ impl Global { profiling::scope!("Device::create_tlas"); let hub = &self.hub; - let fid = hub.tlas_s.prepare(device_id.backend(), id_in); + let fid = hub.tlas_s.prepare(id_in); let device_guard = hub.devices.read(); let error = 'error: { - let device = match device_guard.get(device_id) { - Ok(device) => device, - Err(_) => break 'error DeviceError::InvalidDeviceId.into(), - }; + let device = device_guard.get(device_id); + match device.check_is_valid() { + Ok(_) => {} + Err(e) => break 'error CreateTlasError::Device(e), + } #[cfg(feature = "trace")] if let Some(trace) = device.trace.lock().as_mut() { trace.add(trace::Action::CreateTlas { @@ -229,13 +228,13 @@ impl Global { Err(e) => break 'error e, }; - let id = fid.assign(tlas.clone()); + let id = fid.assign(Fallible::Valid(tlas)); log::info!("Created tlas {:?} with {:?}", id, desc); return (id, None); }; - let id = fid.assign_error(); + let id = fid.assign(Fallible::Invalid(Arc::new(error.to_string()))); (id, Some(error)) } @@ -248,7 +247,8 @@ impl Global { let blas_guard = hub.blas_s.write(); let blas = blas_guard .get(blas_id) - .map_err(|_| resource::DestroyError::Invalid)? + .get() + .map_err(resource::DestroyError::InvalidResource)? .clone(); drop(blas_guard); let device = &blas.device; @@ -276,9 +276,9 @@ impl Global { let hub = &self.hub; - let _blas = match hub.blas_s.unregister(blas_id) { - Some(blas) => blas, - None => { + let _blas = match hub.blas_s.remove(blas_id).get() { + Ok(blas) => blas, + Err(_) => { return; } }; @@ -302,7 +302,8 @@ impl Global { let tlas_guard = hub.tlas_s.write(); let tlas = tlas_guard .get(tlas_id) - .map_err(|_| resource::DestroyError::Invalid)? + .get() + .map_err(resource::DestroyError::InvalidResource)? .clone(); drop(tlas_guard); @@ -331,9 +332,9 @@ impl Global { let hub = &self.hub; - let _tlas = match hub.tlas_s.unregister(tlas_id) { - Some(tlas) => tlas, - None => { + let _tlas = match hub.tlas_s.remove(tlas_id).get() { + Ok(tlas) => tlas, + Err(_) => { return; } }; diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 49dc487b82..ab54ddb7df 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -21,7 +21,7 @@ use crate::{ pipeline, pool::ResourcePool, resource::{ - self, Buffer, Labeled, ParentDevice, QuerySet, Sampler, StagingBuffer, Texture, + self, Buffer, Fallible, Labeled, ParentDevice, QuerySet, Sampler, StagingBuffer, Texture, TextureView, TextureViewNotRenderableReason, TrackingData, }, resource_log, @@ -39,7 +39,9 @@ use once_cell::sync::OnceCell; use smallvec::SmallVec; use thiserror::Error; -use wgt::{DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension}; +use wgt::{ + math::align_to, DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension, +}; use crate::resource::{AccelerationStructure, Tlas}; use std::{ @@ -227,31 +229,29 @@ impl Device { desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, instance_flags: wgt::InstanceFlags, - ) -> Result { + ) -> Result { #[cfg(not(feature = "trace"))] if let Some(_) = trace_path { log::error!("Feature 'trace' is not enabled"); } - let fence = - unsafe { raw_device.create_fence() }.map_err(|_| CreateDeviceError::OutOfMemory)?; + let fence = unsafe { raw_device.create_fence() }.map_err(DeviceError::from_hal)?; let command_allocator = command::CommandAllocator::new(); let pending_encoder = command_allocator .acquire_encoder(raw_device.as_ref(), raw_queue) - .map_err(|_| CreateDeviceError::OutOfMemory)?; + .map_err(DeviceError::from_hal)?; let mut pending_writes = PendingWrites::new(pending_encoder); // Create zeroed buffer used for texture clears. let zero_buffer = unsafe { - raw_device - .create_buffer(&hal::BufferDescriptor { - label: hal_label(Some("(wgpu internal) zero init buffer"), instance_flags), - size: ZERO_BUFFER_SIZE, - usage: hal::BufferUses::COPY_SRC | hal::BufferUses::COPY_DST, - memory_flags: hal::MemoryFlags::empty(), - }) - .map_err(DeviceError::from)? - }; + raw_device.create_buffer(&hal::BufferDescriptor { + label: hal_label(Some("(wgpu internal) zero init buffer"), instance_flags), + size: ZERO_BUFFER_SIZE, + usage: hal::BufferUses::COPY_SRC | hal::BufferUses::COPY_DST, + memory_flags: hal::MemoryFlags::empty(), + }) + } + .map_err(DeviceError::from_hal)?; pending_writes.activate(); unsafe { pending_writes @@ -340,10 +340,23 @@ impl Device { } } + pub fn handle_hal_error(&self, error: hal::DeviceError) -> DeviceError { + match error { + hal::DeviceError::OutOfMemory => {} + hal::DeviceError::Lost + | hal::DeviceError::ResourceCreationFailed + | hal::DeviceError::Unexpected => { + self.lose(&error.to_string()); + } + } + DeviceError::from_hal(error) + } + pub(crate) fn release_queue(&self, queue: Box) { assert!(self.queue_to_drop.set(queue).is_ok()); } + #[track_caller] pub(crate) fn lock_life<'a>(&'a self) -> MutexGuard<'a, LifetimeTracker> { self.life_tracker.lock() } @@ -441,11 +454,8 @@ impl Device { wgt::Maintain::Wait => self .last_successful_submission_index .load(Ordering::Acquire), - wgt::Maintain::Poll => unsafe { - self.raw() - .get_fence_value(fence.as_ref()) - .map_err(DeviceError::from)? - }, + wgt::Maintain::Poll => unsafe { self.raw().get_fence_value(fence.as_ref()) } + .map_err(|e| self.handle_hal_error(e))?, }; // If necessary, wait for that submission to complete. @@ -453,8 +463,8 @@ impl Device { unsafe { self.raw() .wait(fence.as_ref(), submission_index, CLEANUP_WAIT_MS) - .map_err(DeviceError::from)? - }; + } + .map_err(|e| self.handle_hal_error(e))?; } log::trace!("Device::maintain: waiting for submission index {submission_index}"); @@ -588,7 +598,8 @@ impl Device { usage, memory_flags: hal::MemoryFlags::empty(), }; - let buffer = unsafe { self.raw().create_buffer(&hal_desc) }.map_err(DeviceError::from)?; + let buffer = + unsafe { self.raw().create_buffer(&hal_desc) }.map_err(|e| self.handle_hal_error(e))?; let buffer = Buffer { raw: Snatchable::new(buffer), @@ -664,6 +675,8 @@ impl Device { .describe_format_features(desc.format) .map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))?; + unsafe { self.raw().add_raw_texture(&*hal_texture) }; + let texture = Texture::new( self, resource::TextureInner::Native { raw: hal_texture }, @@ -684,11 +697,13 @@ impl Device { Ok(texture) } - pub fn create_buffer_from_hal( + pub(crate) fn create_buffer_from_hal( self: &Arc, hal_buffer: Box, desc: &resource::BufferDescriptor, - ) -> Arc { + ) -> Fallible { + unsafe { self.raw().add_raw_buffer(&*hal_buffer) }; + let buffer = Buffer { raw: Snatchable::new(hal_buffer), device: self.clone(), @@ -711,7 +726,7 @@ impl Device { .buffers .insert_single(&buffer, hal::BufferUses::empty()); - buffer + Fallible::Valid(buffer) } pub(crate) fn create_texture( @@ -931,11 +946,8 @@ impl Device { view_formats: hal_view_formats, }; - let raw_texture = unsafe { - self.raw() - .create_texture(&hal_desc) - .map_err(DeviceError::from)? - }; + let raw_texture = unsafe { self.raw().create_texture(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; let clear_mode = if hal_usage .intersects(hal::TextureUses::DEPTH_STENCIL_WRITE | hal::TextureUses::COLOR_TARGET) @@ -978,7 +990,7 @@ impl Device { unsafe { self.raw().create_texture_view(raw_texture.as_ref(), &desc) } - .map_err(DeviceError::from)?, + .map_err(|e| self.handle_hal_error(e))?, )); }; } @@ -1284,11 +1296,8 @@ impl Device { range: resolved_range, }; - let raw = unsafe { - self.raw() - .create_texture_view(texture_raw, &hal_desc) - .map_err(|_| resource::CreateTextureViewError::OutOfMemory)? - }; + let raw = unsafe { self.raw().create_texture_view(texture_raw, &hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; let selector = TextureSelector { mips: desc.range.base_mip_level..mip_level_end, @@ -1419,11 +1428,8 @@ impl Device { border_color: desc.border_color, }; - let raw = unsafe { - self.raw() - .create_sampler(&hal_desc) - .map_err(DeviceError::from)? - }; + let raw = unsafe { self.raw().create_sampler(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; let sampler = Sampler { raw: ManuallyDrop::new(raw), @@ -1547,7 +1553,7 @@ impl Device { Err(error) => { return Err(match error { hal::ShaderError::Device(error) => { - pipeline::CreateShaderModuleError::Device(error.into()) + pipeline::CreateShaderModuleError::Device(self.handle_hal_error(error)) } hal::ShaderError::Compilation(ref msg) => { log::error!("Shader error: {}", msg); @@ -1588,7 +1594,7 @@ impl Device { Err(error) => { return Err(match error { hal::ShaderError::Device(error) => { - pipeline::CreateShaderModuleError::Device(error.into()) + pipeline::CreateShaderModuleError::Device(self.handle_hal_error(error)) } hal::ShaderError::Compilation(ref msg) => { log::error!("Shader error: {}", msg); @@ -1620,7 +1626,8 @@ impl Device { let encoder = self .command_allocator - .acquire_encoder(self.raw(), queue.raw())?; + .acquire_encoder(self.raw(), queue.raw()) + .map_err(|e| self.handle_hal_error(e))?; let command_buffer = command::CommandBuffer::new(encoder, self, label); @@ -1631,7 +1638,7 @@ impl Device { /// Generate information about late-validated buffer bindings for pipelines. //TODO: should this be combined with `get_introspection_bind_group_layouts` in some way? - pub(crate) fn make_late_sized_buffer_groups( + fn make_late_sized_buffer_groups( shader_binding_sizes: &FastHashMap, layout: &binding_model::PipelineLayout, ) -> ArrayVec { @@ -1852,11 +1859,9 @@ impl Device { flags: bgl_flags, entries: &hal_bindings, }; - let raw = unsafe { - self.raw() - .create_bind_group_layout(&hal_desc) - .map_err(DeviceError::from)? - }; + + let raw = unsafe { self.raw().create_bind_group_layout(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; let mut count_validator = binding_model::BindingTypeMaxCountValidator::default(); for entry in entry_map.values() { @@ -1883,8 +1888,8 @@ impl Device { Ok(bgl) } - pub(crate) fn create_buffer_binding<'a>( - self: &Arc, + fn create_buffer_binding<'a>( + &self, bb: &'a binding_model::ResolvedBufferBinding, binding: u32, decl: &wgt::BindGroupLayoutEntry, @@ -1892,7 +1897,6 @@ impl Device { dynamic_binding_info: &mut Vec, late_buffer_binding_sizes: &mut FastHashMap, used: &mut BindGroupStates, - limits: &wgt::Limits, snatch_guard: &'a SnatchGuard<'a>, ) -> Result, binding_model::CreateBindGroupError> { @@ -1917,7 +1921,7 @@ impl Device { wgt::BufferBindingType::Uniform => ( wgt::BufferUsages::UNIFORM, hal::BufferUses::UNIFORM, - limits.max_uniform_buffer_binding_size, + self.limits.max_uniform_buffer_binding_size, ), wgt::BufferBindingType::Storage { read_only } => ( wgt::BufferUsages::STORAGE, @@ -1926,12 +1930,12 @@ impl Device { } else { hal::BufferUses::STORAGE_READ_WRITE }, - limits.max_storage_buffer_binding_size, + self.limits.max_storage_buffer_binding_size, ), }; let (align, align_limit_name) = - binding_model::buffer_binding_type_alignment(limits, binding_ty); + binding_model::buffer_binding_type_alignment(&self.limits, binding_ty); if bb.offset % align as u64 != 0 { return Err(Error::UnalignedBufferOffset( bb.offset, @@ -2007,10 +2011,21 @@ impl Device { late_buffer_binding_sizes.insert(binding, late_size); } + // This was checked against the device's alignment requirements above, + // which should always be a multiple of `COPY_BUFFER_ALIGNMENT`. assert_eq!(bb.offset % wgt::COPY_BUFFER_ALIGNMENT, 0); + + // `wgpu_hal` only restricts shader access to bound buffer regions with + // a certain resolution. For the sake of lazy initialization, round up + // the size of the bound range to reflect how much of the buffer is + // actually going to be visible to the shader. + let bounds_check_alignment = + binding_model::buffer_binding_type_bounds_check_alignment(&self.alignments, binding_ty); + let visible_size = align_to(bind_size, bounds_check_alignment); + used_buffer_ranges.extend(buffer.initialization_status.read().create_action( buffer, - bb.offset..bb.offset + bind_size, + bb.offset..bb.offset + visible_size, MemoryInitKind::NeedsInitializedMemory, )); @@ -2022,7 +2037,7 @@ impl Device { } fn create_sampler_binding<'a>( - self: &Arc, + &self, used: &mut BindGroupStates, binding: u32, decl: &wgt::BindGroupLayoutEntry, @@ -2070,8 +2085,8 @@ impl Device { Ok(sampler.raw()) } - pub(crate) fn create_texture_binding<'a>( - self: &Arc, + fn create_texture_binding<'a>( + &self, binding: u32, decl: &wgt::BindGroupLayoutEntry, view: &'a Arc, @@ -2197,7 +2212,6 @@ impl Device { &mut dynamic_binding_info, &mut late_buffer_binding_sizes, &mut used, - &self.limits, &snatch_guard, )?; @@ -2219,7 +2233,6 @@ impl Device { &mut dynamic_binding_info, &mut late_buffer_binding_sizes, &mut used, - &self.limits, &snatch_guard, )?; hal_buffers.push(bb); @@ -2312,11 +2325,8 @@ impl Device { textures: &hal_textures, acceleration_structures: &hal_tlas_s, }; - let raw = unsafe { - self.raw() - .create_bind_group(&hal_desc) - .map_err(DeviceError::from)? - }; + let raw = unsafe { self.raw().create_bind_group(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; // collect in the order of BGL iteration let late_buffer_binding_sizes = layout @@ -2361,7 +2371,7 @@ impl Device { Ok(bind_group) } - pub(crate) fn check_array_binding( + fn check_array_binding( features: wgt::Features, count: Option, num_bindings: usize, @@ -2394,8 +2404,8 @@ impl Device { Ok(()) } - pub(crate) fn texture_use_parameters( - self: &Arc, + fn texture_use_parameters( + &self, binding: u32, decl: &wgt::BindGroupLayoutEntry, view: &TextureView, @@ -2610,11 +2620,8 @@ impl Device { push_constant_ranges: desc.push_constant_ranges.as_ref(), }; - let raw = unsafe { - self.raw() - .create_pipeline_layout(&hal_desc) - .map_err(DeviceError::from)? - }; + let raw = unsafe { self.raw().create_pipeline_layout(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; drop(raw_bind_group_layouts); @@ -2768,7 +2775,7 @@ impl Device { unsafe { self.raw().create_compute_pipeline(&pipeline_desc) }.map_err( |err| match err { hal::PipelineError::Device(error) => { - pipeline::CreateComputePipelineError::Device(error.into()) + pipeline::CreateComputePipelineError::Device(self.handle_hal_error(error)) } hal::PipelineError::Linkage(_stages, msg) => { pipeline::CreateComputePipelineError::Internal(msg) @@ -3348,7 +3355,7 @@ impl Device { unsafe { self.raw().create_render_pipeline(&pipeline_desc) }.map_err( |err| match err { hal::PipelineError::Device(error) => { - pipeline::CreateRenderPipelineError::Device(error.into()) + pipeline::CreateRenderPipelineError::Device(self.handle_hal_error(error)) } hal::PipelineError::Linkage(stage, msg) => { pipeline::CreateRenderPipelineError::Internal { stage, error: msg } @@ -3471,7 +3478,9 @@ impl Device { }; let raw = match unsafe { self.raw().create_pipeline_cache(&cache_desc) } { Ok(raw) => raw, - Err(e) => return Err(e.into()), + Err(e) => match e { + hal::PipelineCacheError::Device(e) => return Err(self.handle_hal_error(e).into()), + }, }; let cache = pipeline::PipelineCache { device: self.clone(), @@ -3485,10 +3494,7 @@ impl Device { Ok(cache) } - pub(crate) fn get_texture_format_features( - &self, - format: TextureFormat, - ) -> wgt::TextureFormatFeatures { + fn get_texture_format_features(&self, format: TextureFormat) -> wgt::TextureFormatFeatures { // Variant of adapter.get_texture_format_features that takes device features into account use wgt::TextureFormatFeatureFlags as tfsc; let mut format_features = self.adapter.get_texture_format_features(format); @@ -3502,7 +3508,7 @@ impl Device { format_features } - pub(crate) fn describe_format_features( + fn describe_format_features( &self, format: TextureFormat, ) -> Result { @@ -3531,9 +3537,11 @@ impl Device { submission_index: crate::SubmissionIndex, ) -> Result<(), DeviceError> { let fence = self.fence.read(); - let last_done_index = unsafe { self.raw().get_fence_value(fence.as_ref())? }; + let last_done_index = unsafe { self.raw().get_fence_value(fence.as_ref()) } + .map_err(|e| self.handle_hal_error(e))?; if last_done_index < submission_index { - unsafe { self.raw().wait(fence.as_ref(), submission_index, !0)? }; + unsafe { self.raw().wait(fence.as_ref(), submission_index, !0) } + .map_err(|e| self.handle_hal_error(e))?; drop(fence); let closures = self .lock_life() @@ -3592,7 +3600,7 @@ impl Device { Ok(query_set) } - pub(crate) fn lose(&self, message: &str) { + fn lose(&self, message: &str) { // Follow the steps at https://gpuweb.github.io/gpuweb/#lose-the-device. // Mark the device explicitly as invalid. This is checked in various @@ -3659,16 +3667,6 @@ impl Device { } impl Device { - pub(crate) fn destroy_command_buffer(&self, mut cmd_buf: command::CommandBuffer) { - let mut baked = cmd_buf.extract_baked_commands(); - unsafe { - baked.encoder.reset_all(baked.list); - } - unsafe { - self.raw().destroy_command_encoder(baked.encoder); - } - } - /// Wait for idle and remove resources that we can, before we die. pub(crate) fn prepare_to_die(&self) { self.pending_writes.lock().deactivate(); diff --git a/wgpu-core/src/error.rs b/wgpu-core/src/error.rs index aa1f11df0f..519a5f930c 100644 --- a/wgpu-core/src/error.rs +++ b/wgpu-core/src/error.rs @@ -3,6 +3,11 @@ use std::{error::Error, sync::Arc}; use thiserror::Error; +#[cfg(send_sync)] +pub type ContextErrorSource = Box; +#[cfg(not(send_sync))] +pub type ContextErrorSource = Box; + #[derive(Debug, Error)] #[error( "In {fn_ident}{}{}{}", @@ -13,10 +18,7 @@ use thiserror::Error; pub struct ContextError { pub fn_ident: &'static str, #[source] - #[cfg(send_sync)] - pub source: Box, - #[cfg(not(send_sync))] - pub source: Box, + pub source: ContextErrorSource, pub label: String, } diff --git a/wgpu-core/src/global.rs b/wgpu-core/src/global.rs index 4d79a81e3b..bb672612e4 100644 --- a/wgpu-core/src/global.rs +++ b/wgpu-core/src/global.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::{ hal_api::HalApi, hub::{Hub, HubReport}, @@ -23,7 +25,7 @@ impl GlobalReport { pub struct Global { pub instance: Instance, - pub(crate) surfaces: Registry, + pub(crate) surfaces: Registry>, pub(crate) hub: Hub, } diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 82d45c964b..1a564ebfcc 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -107,10 +107,12 @@ use crate::{ instance::{Adapter, Surface}, pipeline::{ComputePipeline, PipelineCache, RenderPipeline, ShaderModule}, registry::{Registry, RegistryReport}, - resource::{Blas, Buffer, QuerySet, Sampler, StagingBuffer, Texture, TextureView, Tlas}, + resource::{ + Blas, Buffer, Fallible, QuerySet, Sampler, StagingBuffer, Texture, TextureView, Tlas, + }, storage::{Element, Storage}, }; -use std::fmt::Debug; +use std::{fmt::Debug, sync::Arc}; #[derive(Debug, PartialEq, Eq)] pub struct HubReport { @@ -162,26 +164,26 @@ impl HubReport { /// /// [`A::hub(global)`]: HalApi::hub pub struct Hub { - pub(crate) adapters: Registry, - pub(crate) devices: Registry, - pub(crate) queues: Registry, - pub(crate) pipeline_layouts: Registry, - pub(crate) shader_modules: Registry, - pub(crate) bind_group_layouts: Registry, - pub(crate) bind_groups: Registry, - pub(crate) command_buffers: Registry, - pub(crate) render_bundles: Registry, - pub(crate) render_pipelines: Registry, - pub(crate) compute_pipelines: Registry, - pub(crate) pipeline_caches: Registry, - pub(crate) query_sets: Registry, - pub(crate) buffers: Registry, + pub(crate) adapters: Registry>, + pub(crate) devices: Registry>, + pub(crate) queues: Registry>, + pub(crate) pipeline_layouts: Registry>, + pub(crate) shader_modules: Registry>, + pub(crate) bind_group_layouts: Registry>, + pub(crate) bind_groups: Registry>, + pub(crate) command_buffers: Registry>, + pub(crate) render_bundles: Registry>, + pub(crate) render_pipelines: Registry>, + pub(crate) compute_pipelines: Registry>, + pub(crate) pipeline_caches: Registry>, + pub(crate) query_sets: Registry>, + pub(crate) buffers: Registry>, pub(crate) staging_buffers: Registry, - pub(crate) textures: Registry, - pub(crate) texture_views: Registry, - pub(crate) samplers: Registry, - pub(crate) blas_s: Registry, - pub(crate) tlas_s: Registry, + pub(crate) textures: Registry>, + pub(crate) texture_views: Registry>, + pub(crate) samplers: Registry>, + pub(crate) blas_s: Registry>, + pub(crate) tlas_s: Registry>, } impl Hub { @@ -210,7 +212,7 @@ impl Hub { } } - pub(crate) fn clear(&self, surface_guard: &Storage) { + pub(crate) fn clear(&self, surface_guard: &Storage>) { let mut devices = self.devices.write(); for element in devices.map.iter() { if let Element::Occupied(ref device, _) = *element { diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index 3c00f755df..2fdfde9116 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -4,18 +4,26 @@ use std::{ fmt::{self, Debug}, hash::Hash, marker::PhantomData, + mem::size_of, + num::NonZeroU64, }; -use wgt::{Backend, WasmNotSendSync}; +use wgt::WasmNotSendSync; -type IdType = u64; -type ZippedIndex = Index; -type NonZeroId = std::num::NonZeroU64; - -const INDEX_BITS: usize = ZippedIndex::BITS as usize; -const EPOCH_BITS: usize = INDEX_BITS - BACKEND_BITS; -const BACKEND_BITS: usize = 3; -const BACKEND_SHIFT: usize = INDEX_BITS * 2 - BACKEND_BITS; -pub const EPOCH_MASK: u32 = (1 << (EPOCH_BITS)) - 1; +const _: () = { + if size_of::() != 4 { + panic!() + } +}; +const _: () = { + if size_of::() != 4 { + panic!() + } +}; +const _: () = { + if size_of::() != 8 { + panic!() + } +}; /// The raw underlying representation of an identifier. #[repr(transparent)] @@ -30,50 +38,18 @@ pub const EPOCH_MASK: u32 = (1 << (EPOCH_BITS)) - 1; serde(from = "SerialId") )] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct RawId(NonZeroId); +pub struct RawId(NonZeroU64); impl RawId { - #[doc(hidden)] - #[inline] - pub fn from_non_zero(non_zero: NonZeroId) -> Self { - Self(non_zero) - } - - #[doc(hidden)] - #[inline] - pub fn into_non_zero(self) -> NonZeroId { - self.0 - } - /// Zip together an identifier and return its raw underlying representation. - pub fn zip(index: Index, epoch: Epoch, backend: Backend) -> RawId { - assert_eq!(0, epoch >> EPOCH_BITS); - assert_eq!(0, (index as IdType) >> INDEX_BITS); - let v = index as IdType - | ((epoch as IdType) << INDEX_BITS) - | ((backend as IdType) << BACKEND_SHIFT); - Self(NonZeroId::new(v).unwrap()) + pub fn zip(index: Index, epoch: Epoch) -> RawId { + let v = (index as u64) | ((epoch as u64) << 32); + Self(NonZeroU64::new(v).unwrap()) } /// Unzip a raw identifier into its components. - #[allow(trivial_numeric_casts)] - pub fn unzip(self) -> (Index, Epoch, Backend) { - ( - (self.0.get() as ZippedIndex) as Index, - (((self.0.get() >> INDEX_BITS) as ZippedIndex) & (EPOCH_MASK as ZippedIndex)) as Index, - self.backend(), - ) - } - - pub fn backend(self) -> Backend { - match self.0.get() >> (BACKEND_SHIFT) as u8 { - 0 => Backend::Empty, - 1 => Backend::Vulkan, - 2 => Backend::Metal, - 3 => Backend::Dx12, - 4 => Backend::Gl, - _ => unreachable!(), - } + pub fn unzip(self) -> (Index, Epoch) { + (self.0.get() as Index, (self.0.get() >> 32) as Epoch) } } @@ -116,20 +92,20 @@ pub struct Id(RawId, PhantomData); #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] enum SerialId { // The only variant forces RON to not ignore "Id" - Id(Index, Epoch, Backend), + Id(Index, Epoch), } impl From for SerialId { fn from(id: RawId) -> Self { - let (index, epoch, backend) = id.unzip(); - Self::Id(index, epoch, backend) + let (index, epoch) = id.unzip(); + Self::Id(index, epoch) } } impl From for RawId { fn from(id: SerialId) -> Self { match id { - SerialId::Id(index, epoch, backend) => RawId::zip(index, epoch, backend), + SerialId::Id(index, epoch) => RawId::zip(index, epoch), } } } @@ -150,29 +126,13 @@ where self.0 } - #[allow(dead_code)] - pub(crate) fn dummy(index: u32) -> Self { - Id::zip(index, 1, Backend::Empty) - } - - #[allow(dead_code)] - pub(crate) fn is_valid(&self) -> bool { - self.backend() != Backend::Empty - } - - /// Get the backend this identifier corresponds to. #[inline] - pub fn backend(self) -> Backend { - self.0.backend() + pub fn zip(index: Index, epoch: Epoch) -> Self { + Id(RawId::zip(index, epoch), PhantomData) } #[inline] - pub fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self { - Id(RawId::zip(index, epoch, backend), PhantomData) - } - - #[inline] - pub fn unzip(self) -> (Index, Epoch, Backend) { + pub fn unzip(self) -> (Index, Epoch) { self.0.unzip() } } @@ -194,16 +154,8 @@ where T: Marker, { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let (index, epoch, backend) = self.unzip(); - let backend = match backend { - Backend::Empty => "_", - Backend::Vulkan => "vk", - Backend::Metal => "mtl", - Backend::Dx12 => "d3d12", - Backend::Gl => "gl", - Backend::BrowserWebGpu => "webgpu", - }; - write!(formatter, "Id({index},{epoch},{backend})")?; + let (index, epoch) = self.unzip(); + write!(formatter, "Id({index},{epoch})")?; Ok(()) } } @@ -328,43 +280,16 @@ impl CommandBufferId { } } -#[test] -fn test_id_backend() { - for &b in &[ - Backend::Empty, - Backend::Vulkan, - Backend::Metal, - Backend::Dx12, - Backend::Gl, - ] { - let id = Id::<()>::zip(1, 0, b); - let (_id, _epoch, backend) = id.unzip(); - assert_eq!(id.backend(), b); - assert_eq!(backend, b); - } -} - #[test] fn test_id() { - let last_index = ((1u64 << INDEX_BITS) - 1) as Index; - let indexes = [1, last_index / 2 - 1, last_index / 2 + 1, last_index]; - let epochs = [1, EPOCH_MASK / 2 - 1, EPOCH_MASK / 2 + 1, EPOCH_MASK]; - let backends = [ - Backend::Empty, - Backend::Vulkan, - Backend::Metal, - Backend::Dx12, - Backend::Gl, - ]; + let indexes = [0, Index::MAX / 2 - 1, Index::MAX / 2 + 1, Index::MAX]; + let epochs = [1, Epoch::MAX / 2 - 1, Epoch::MAX / 2 + 1, Epoch::MAX]; for &i in &indexes { for &e in &epochs { - for &b in &backends { - let id = Id::<()>::zip(i, e, b); - let (index, epoch, backend) = id.unzip(); - assert_eq!(index, i); - assert_eq!(epoch, e); - assert_eq!(backend, b); - } + let id = Id::<()>::zip(i, e); + let (index, epoch) = id.unzip(); + assert_eq!(index, i); + assert_eq!(epoch, e); } } } diff --git a/wgpu-core/src/identity.rs b/wgpu-core/src/identity.rs index c89731f7af..0493b9d2cf 100644 --- a/wgpu-core/src/identity.rs +++ b/wgpu-core/src/identity.rs @@ -1,5 +1,3 @@ -use wgt::Backend; - use crate::{ id::{Id, Marker}, lock::{rank, Mutex}, @@ -52,7 +50,7 @@ impl IdentityValues { /// /// The backend is incorporated into the id, so that ids allocated with /// different `backend` values are always distinct. - pub fn alloc(&mut self, backend: Backend) -> Id { + pub fn alloc(&mut self) -> Id { assert!( self.id_source != IdSource::External, "Mix of internally allocated and externally provided IDs" @@ -61,12 +59,12 @@ impl IdentityValues { self.count += 1; match self.free.pop() { - Some((index, epoch)) => Id::zip(index, epoch + 1, backend), + Some((index, epoch)) => Id::zip(index, epoch + 1), None => { let index = self.next_index; self.next_index += 1; let epoch = 1; - Id::zip(index, epoch, backend) + Id::zip(index, epoch) } } } @@ -85,7 +83,7 @@ impl IdentityValues { /// Free `id`. It will never be returned from `alloc` again. pub fn release(&mut self, id: Id) { if let IdSource::Allocated = self.id_source { - let (index, epoch, _backend) = id.unzip(); + let (index, epoch) = id.unzip(); self.free.push((index, epoch)); } self.count -= 1; @@ -103,8 +101,8 @@ pub struct IdentityManager { } impl IdentityManager { - pub fn process(&self, backend: Backend) -> Id { - self.values.lock().alloc(backend) + pub fn process(&self) -> Id { + self.values.lock().alloc() } pub fn mark_as_used(&self, id: Id) -> Id { self.values.lock().mark_as_used(id) @@ -135,10 +133,10 @@ impl IdentityManager { fn test_epoch_end_of_life() { use crate::id; let man = IdentityManager::::new(); - let id1 = man.process(Backend::Empty); - assert_eq!(id1.unzip(), (0, 1, Backend::Empty)); + let id1 = man.process(); + assert_eq!(id1.unzip(), (0, 1)); man.free(id1); - let id2 = man.process(Backend::Empty); + let id2 = man.process(); // confirm that the epoch 1 is no longer re-used - assert_eq!(id2.unzip(), (0, 2, Backend::Empty)); + assert_eq!(id2.unzip(), (0, 2)); } diff --git a/wgpu-core/src/init_tracker/mod.rs b/wgpu-core/src/init_tracker/mod.rs index ccaac1e16f..15a79bf520 100644 --- a/wgpu-core/src/init_tracker/mod.rs +++ b/wgpu-core/src/init_tracker/mod.rs @@ -65,6 +65,35 @@ pub(crate) struct InitTracker { uninitialized_ranges: UninitializedRangeVec, } +pub(crate) struct UninitializedIter<'a, Idx: fmt::Debug + Ord + Copy> { + uninitialized_ranges: &'a UninitializedRangeVec, + drain_range: Range, + next_index: usize, +} + +impl<'a, Idx> Iterator for UninitializedIter<'a, Idx> +where + Idx: fmt::Debug + Ord + Copy, +{ + type Item = Range; + + fn next(&mut self) -> Option { + self.uninitialized_ranges + .get(self.next_index) + .and_then(|range| { + if range.start < self.drain_range.end { + self.next_index += 1; + Some( + range.start.max(self.drain_range.start) + ..range.end.min(self.drain_range.end), + ) + } else { + None + } + }) + } +} + pub(crate) struct InitTrackerDrain<'a, Idx: fmt::Debug + Ord + Copy> { uninitialized_ranges: &'a mut UninitializedRangeVec, drain_range: Range, @@ -190,6 +219,18 @@ where }) } + // Returns an iterator over the uninitialized ranges in a query range. + pub(crate) fn uninitialized(&mut self, drain_range: Range) -> UninitializedIter { + let index = self + .uninitialized_ranges + .partition_point(|r| r.end <= drain_range.start); + UninitializedIter { + drain_range, + uninitialized_ranges: &self.uninitialized_ranges, + next_index: index, + } + } + // Drains uninitialized ranges in a query range. pub(crate) fn drain(&mut self, drain_range: Range) -> InitTrackerDrain { let index = self diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index a71117cfe1..581c5ce0d9 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -1,13 +1,12 @@ use std::sync::Arc; use std::{borrow::Cow, collections::HashMap}; -use crate::hub::Hub; use crate::{ api_log, - device::{queue::Queue, resource::Device, DeviceDescriptor}, + device::{queue::Queue, resource::Device, DeviceDescriptor, DeviceError}, global::Global, hal_api::HalApi, - id::{markers, AdapterId, DeviceId, Id, Marker, QueueId, SurfaceId}, + id::{markers, AdapterId, DeviceId, QueueId, SurfaceId}, lock::{rank, Mutex}, present::Presentation, resource::ResourceType, @@ -272,20 +271,19 @@ impl Adapter { ) -> Result<(Arc, Arc), RequestDeviceError> { api_log!("Adapter::create_device"); - if let Ok(device) = Device::new( + let device = Device::new( hal_device.device, hal_device.queue.as_ref(), self, desc, trace_path, instance_flags, - ) { - let device = Arc::new(device); - let queue = Arc::new(Queue::new(device.clone(), hal_device.queue)); - device.set_queue(&queue); - return Ok((device, queue)); - } - Err(RequestDeviceError::OutOfMemory) + )?; + + let device = Arc::new(device); + let queue = Arc::new(Queue::new(device.clone(), hal_device.queue)); + device.set_queue(&queue); + Ok((device, queue)) } #[allow(clippy::type_complexity)] @@ -338,11 +336,7 @@ impl Adapter { &desc.memory_hints, ) } - .map_err(|err| match err { - hal::DeviceError::Lost => RequestDeviceError::DeviceLost, - hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory, - hal::DeviceError::ResourceCreationFailed => RequestDeviceError::Internal, - })?; + .map_err(DeviceError::from_hal)?; self.create_device_and_queue_from_hal(open, desc, instance_flags, trace_path) } @@ -351,22 +345,9 @@ impl Adapter { crate::impl_resource_type!(Adapter); crate::impl_storage_item!(Adapter); -#[derive(Clone, Debug, Error)] -#[non_exhaustive] -pub enum IsSurfaceSupportedError { - #[error("Invalid adapter")] - InvalidAdapter, - #[error("Invalid surface")] - InvalidSurface, -} - #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum GetSurfaceSupportError { - #[error("Invalid adapter")] - InvalidAdapter, - #[error("Invalid surface")] - InvalidSurface, #[error("Surface is not supported by the adapter")] Unsupported, } @@ -376,54 +357,22 @@ pub enum GetSurfaceSupportError { /// Error when requesting a device from the adaptor #[non_exhaustive] pub enum RequestDeviceError { - #[error("Parent adapter is invalid")] - InvalidAdapter, - #[error("Connection to device was lost during initialization")] - DeviceLost, - #[error("Device initialization failed due to implementation specific errors")] - Internal, + #[error(transparent)] + Device(#[from] DeviceError), #[error(transparent)] LimitsExceeded(#[from] FailedLimit), #[error("Device has no queue supporting graphics")] NoGraphicsQueue, - #[error("Not enough memory left to request device")] - OutOfMemory, #[error("Unsupported features were requested: {0:?}")] UnsupportedFeature(wgt::Features), } -pub enum AdapterInputs<'a, M: Marker> { - IdSet(&'a [Id]), - Mask(Backends, fn(Backend) -> Option>), -} - -impl AdapterInputs<'_, M> { - fn find(&self, b: Backend) -> Option>> { - match *self { - Self::IdSet(ids) => Some(Some(ids.iter().find(|id| id.backend() == b).copied()?)), - Self::Mask(bits, ref fun) => { - if bits.contains(b.into()) { - Some(fun(b)) - } else { - None - } - } - } - } -} - -#[derive(Clone, Debug, Error)] -#[error("Adapter is invalid")] -pub struct InvalidAdapter; - #[derive(Clone, Debug, Error)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[non_exhaustive] pub enum RequestAdapterError { #[error("No suitable adapter found")] NotFound, - #[error("Surface {0:?} is invalid")] - InvalidSurface(SurfaceId), } #[derive(Clone, Debug, Error)] @@ -497,7 +446,7 @@ impl Global { let id = self .surfaces - .prepare(wgt::Backend::Empty, id_in) // No specific backend for Surface, since it's not specific. + .prepare(id_in) // No specific backend for Surface, since it's not specific. .assign(Arc::new(surface)); Ok(id) } @@ -541,10 +490,7 @@ impl Global { surface_per_backend: std::iter::once((Backend::Metal, raw_surface)).collect(), }; - let id = self - .surfaces - .prepare(Backend::Metal, id_in) - .assign(Arc::new(surface)); + let id = self.surfaces.prepare(id_in).assign(Arc::new(surface)); Ok(id) } @@ -566,10 +512,7 @@ impl Global { surface_per_backend: std::iter::once((Backend::Dx12, surface)).collect(), }; - let id = self - .surfaces - .prepare(Backend::Dx12, id_in) - .assign(Arc::new(surface)); + let id = self.surfaces.prepare(id_in).assign(Arc::new(surface)); Ok(id) } @@ -584,7 +527,7 @@ impl Global { ) -> Result { profiling::scope!("Instance::instance_create_surface_from_visual"); self.instance_create_surface_dx12(id_in, |inst| unsafe { - inst.create_surface_from_visual(visual.cast()) + inst.create_surface_from_visual(visual) }) } @@ -614,7 +557,7 @@ impl Global { ) -> Result { profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel"); self.instance_create_surface_dx12(id_in, |inst| unsafe { - inst.create_surface_from_swap_chain_panel(swap_chain_panel.cast()) + inst.create_surface_from_swap_chain_panel(swap_chain_panel) }) } @@ -623,9 +566,9 @@ impl Global { api_log!("Surface::drop {id:?}"); - let surface = self.surfaces.unregister(id); - let surface = Arc::into_inner(surface.unwrap()) - .expect("Surface cannot be destroyed because is still in use"); + let surface = self.surfaces.remove(id); + let surface = + Arc::into_inner(surface).expect("Surface cannot be destroyed because is still in use"); if let Some(present) = surface.presentation.lock().take() { for (&backend, surface) in &surface.surface_per_backend { @@ -637,185 +580,81 @@ impl Global { drop(surface) } - pub fn enumerate_adapters(&self, inputs: AdapterInputs) -> Vec { + pub fn enumerate_adapters(&self, backends: Backends) -> Vec { profiling::scope!("Instance::enumerate_adapters"); api_log!("Instance::enumerate_adapters"); - fn enumerate( - hub: &Hub, - backend: Backend, - instance: &dyn hal::DynInstance, - inputs: &AdapterInputs, - list: &mut Vec, - ) { - let Some(id_backend) = inputs.find(backend) else { - return; - }; - + let mut adapters = Vec::new(); + for (_, instance) in self + .instance + .instance_per_backend + .iter() + .filter(|(backend, _)| backends.contains(Backends::from(*backend))) + { profiling::scope!("enumerating", &*format!("{:?}", backend)); let hal_adapters = unsafe { instance.enumerate_adapters(None) }; for raw in hal_adapters { let adapter = Adapter::new(raw); log::info!("Adapter {:?}", adapter.raw.info); - let id = hub - .adapters - .prepare(backend, id_backend) - .assign(Arc::new(adapter)); - list.push(id); + let id = self.hub.adapters.prepare(None).assign(Arc::new(adapter)); + adapters.push(id); } } - - let mut adapters = Vec::new(); - for (backend, instance) in &self.instance.instance_per_backend { - enumerate( - &self.hub, - *backend, - instance.as_ref(), - &inputs, - &mut adapters, - ); - } adapters } - fn select( - &self, - backend: Backend, - selected: &mut usize, - new_id: Option, - mut list: Vec, - ) -> Option { - match selected.checked_sub(list.len()) { - Some(left) => { - *selected = left; - None - } - None => { - let adapter = Adapter::new(list.swap_remove(*selected)); - log::info!("Adapter {:?}", adapter.raw.info); - let id = self - .hub - .adapters - .prepare(backend, new_id) - .assign(Arc::new(adapter)); - Some(id) - } - } - } - pub fn request_adapter( &self, desc: &RequestAdapterOptions, - inputs: AdapterInputs, + backends: Backends, + id_in: Option, ) -> Result { profiling::scope!("Instance::request_adapter"); api_log!("Instance::request_adapter"); - fn gather( - backend: Backend, - instance: &Instance, - inputs: &AdapterInputs, - compatible_surface: Option<&Surface>, - force_software: bool, - device_types: &mut Vec, - ) -> (Option>, Vec) { - let id = inputs.find(backend); - match (id, instance.raw(backend)) { - (Some(id), Some(inst)) => { - let compatible_hal_surface = - compatible_surface.and_then(|surface| surface.raw(backend)); - let mut adapters = unsafe { inst.enumerate_adapters(compatible_hal_surface) }; - if force_software { - adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu); - } - if let Some(surface) = compatible_surface { - adapters - .retain(|exposed| surface.get_capabilities_with_raw(exposed).is_ok()); - } - device_types.extend(adapters.iter().map(|ad| ad.info.device_type)); - (id, adapters) - } - _ => (None, Vec::new()), - } - } - - let compatible_surface = desc - .compatible_surface - .map(|id| { - self.surfaces - .get(id) - .map_err(|_| RequestAdapterError::InvalidSurface(id)) - }) - .transpose()?; + let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id)); let compatible_surface = compatible_surface.as_ref().map(|surface| surface.as_ref()); - let mut device_types = Vec::new(); - - #[cfg(vulkan)] - let (id_vulkan, adapters_vk) = gather( - Backend::Vulkan, - &self.instance, - &inputs, - compatible_surface, - desc.force_fallback_adapter, - &mut device_types, - ); - #[cfg(metal)] - let (id_metal, adapters_metal) = gather( - Backend::Metal, - &self.instance, - &inputs, - compatible_surface, - desc.force_fallback_adapter, - &mut device_types, - ); - #[cfg(dx12)] - let (id_dx12, adapters_dx12) = gather( - Backend::Dx12, - &self.instance, - &inputs, - compatible_surface, - desc.force_fallback_adapter, - &mut device_types, - ); - #[cfg(gles)] - let (id_gl, adapters_gl) = gather( - Backend::Gl, - &self.instance, - &inputs, - compatible_surface, - desc.force_fallback_adapter, - &mut device_types, - ); + let mut adapters = Vec::new(); - if device_types.is_empty() { - return Err(RequestAdapterError::NotFound); + for (backend, instance) in self + .instance + .instance_per_backend + .iter() + .filter(|(backend, _)| backends.contains(Backends::from(*backend))) + { + let compatible_hal_surface = + compatible_surface.and_then(|surface| surface.raw(*backend)); + let mut backend_adapters = + unsafe { instance.enumerate_adapters(compatible_hal_surface) }; + if desc.force_fallback_adapter { + backend_adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu); + } + if let Some(surface) = compatible_surface { + backend_adapters + .retain(|exposed| surface.get_capabilities_with_raw(exposed).is_ok()); + } + adapters.extend(backend_adapters); } - let (mut integrated, mut discrete, mut virt, mut cpu, mut other) = - (None, None, None, None, None); - - for (i, ty) in device_types.into_iter().enumerate() { - match ty { - wgt::DeviceType::IntegratedGpu => { - integrated = integrated.or(Some(i)); - } - wgt::DeviceType::DiscreteGpu => { - discrete = discrete.or(Some(i)); - } - wgt::DeviceType::VirtualGpu => { - virt = virt.or(Some(i)); - } - wgt::DeviceType::Cpu => { - cpu = cpu.or(Some(i)); - } - wgt::DeviceType::Other => { - other = other.or(Some(i)); - } + match desc.power_preference { + PowerPreference::LowPower => { + sort(&mut adapters, true); } + PowerPreference::HighPerformance => { + sort(&mut adapters, false); + } + PowerPreference::None => {} + }; + + fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) { + adapters.sort_by(|a, b| { + get_order(a.info.device_type, prefer_integrated_gpu) + .cmp(&get_order(b.info.device_type, prefer_integrated_gpu)) + }); } - let preferred_gpu = match desc.power_preference { + fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 { // Since devices of type "Other" might really be "Unknown" and come // from APIs like OpenGL that don't specify device type, Prefer more // Specific types over Other. @@ -823,42 +662,28 @@ impl Global { // This means that backends which do provide accurate device types // will be preferred if their device type indicates an actual // hardware GPU (integrated or discrete). - PowerPreference::LowPower => integrated.or(discrete).or(other).or(virt).or(cpu), - PowerPreference::HighPerformance => discrete.or(integrated).or(other).or(virt).or(cpu), - PowerPreference::None => { - let option_min = |a: Option, b: Option| { - if let (Some(a), Some(b)) = (a, b) { - Some(a.min(b)) - } else { - a.or(b) - } - }; - // Pick the lowest id of these types - option_min(option_min(discrete, integrated), other) + match device_type { + wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2, + wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1, + wgt::DeviceType::DiscreteGpu => 1, + wgt::DeviceType::IntegratedGpu => 2, + wgt::DeviceType::Other => 3, + wgt::DeviceType::VirtualGpu => 4, + wgt::DeviceType::Cpu => 5, } - }; - - let mut selected = preferred_gpu.unwrap_or(0); - #[cfg(vulkan)] - if let Some(id) = self.select(Backend::Vulkan, &mut selected, id_vulkan, adapters_vk) { - return Ok(id); } - #[cfg(metal)] - if let Some(id) = self.select(Backend::Metal, &mut selected, id_metal, adapters_metal) { - return Ok(id); - } - #[cfg(dx12)] - if let Some(id) = self.select(Backend::Dx12, &mut selected, id_dx12, adapters_dx12) { - return Ok(id); - } - #[cfg(gles)] - if let Some(id) = self.select(Backend::Gl, &mut selected, id_gl, adapters_gl) { - return Ok(id); - } - let _ = selected; - log::warn!("Some adapters are present, but enumerating them failed!"); - Err(RequestAdapterError::NotFound) + if let Some(adapter) = adapters.into_iter().next() { + log::info!("Adapter {:?}", adapter.info); + let id = self + .hub + .adapters + .prepare(id_in) + .assign(Arc::new(Adapter::new(adapter))); + Ok(id) + } else { + Err(RequestAdapterError::NotFound) + } } /// # Safety @@ -871,80 +696,58 @@ impl Global { ) -> AdapterId { profiling::scope!("Instance::create_adapter_from_hal"); - let fid = self.hub.adapters.prepare(hal_adapter.backend(), input); + let fid = self.hub.adapters.prepare(input); let id = fid.assign(Arc::new(Adapter::new(hal_adapter))); resource_log!("Created Adapter {:?}", id); id } - pub fn adapter_get_info( - &self, - adapter_id: AdapterId, - ) -> Result { - self.hub - .adapters - .get(adapter_id) - .map(|adapter| adapter.raw.info.clone()) - .map_err(|_| InvalidAdapter) + pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo { + let adapter = self.hub.adapters.get(adapter_id); + adapter.raw.info.clone() } pub fn adapter_get_texture_format_features( &self, adapter_id: AdapterId, format: wgt::TextureFormat, - ) -> Result { - self.hub - .adapters - .get(adapter_id) - .map(|adapter| adapter.get_texture_format_features(format)) - .map_err(|_| InvalidAdapter) + ) -> wgt::TextureFormatFeatures { + let adapter = self.hub.adapters.get(adapter_id); + adapter.get_texture_format_features(format) } - pub fn adapter_features(&self, adapter_id: AdapterId) -> Result { - self.hub - .adapters - .get(adapter_id) - .map(|adapter| adapter.raw.features) - .map_err(|_| InvalidAdapter) + pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features { + let adapter = self.hub.adapters.get(adapter_id); + adapter.raw.features } - pub fn adapter_limits(&self, adapter_id: AdapterId) -> Result { - self.hub - .adapters - .get(adapter_id) - .map(|adapter| adapter.raw.capabilities.limits.clone()) - .map_err(|_| InvalidAdapter) + pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits { + let adapter = self.hub.adapters.get(adapter_id); + adapter.raw.capabilities.limits.clone() } pub fn adapter_downlevel_capabilities( &self, adapter_id: AdapterId, - ) -> Result { - self.hub - .adapters - .get(adapter_id) - .map(|adapter| adapter.raw.capabilities.downlevel.clone()) - .map_err(|_| InvalidAdapter) + ) -> wgt::DownlevelCapabilities { + let adapter = self.hub.adapters.get(adapter_id); + adapter.raw.capabilities.downlevel.clone() } pub fn adapter_get_presentation_timestamp( &self, adapter_id: AdapterId, - ) -> Result { - let hub = &self.hub; - - let adapter = hub.adapters.get(adapter_id).map_err(|_| InvalidAdapter)?; - - Ok(unsafe { adapter.raw.adapter.get_presentation_timestamp() }) + ) -> wgt::PresentationTimestamp { + let adapter = self.hub.adapters.get(adapter_id); + unsafe { adapter.raw.adapter.get_presentation_timestamp() } } pub fn adapter_drop(&self, adapter_id: AdapterId) { profiling::scope!("Adapter::drop"); api_log!("Adapter::drop {adapter_id:?}"); - let hub = &self.hub; - hub.adapters.unregister(adapter_id); + self.hub.adapters.remove(adapter_id); } } @@ -956,37 +759,24 @@ impl Global { trace_path: Option<&std::path::Path>, device_id_in: Option, queue_id_in: Option, - ) -> (DeviceId, QueueId, Option) { + ) -> Result<(DeviceId, QueueId), RequestDeviceError> { profiling::scope!("Adapter::request_device"); api_log!("Adapter::request_device"); - let backend = adapter_id.backend(); - let device_fid = self.hub.devices.prepare(backend, device_id_in); - let queue_fid = self.hub.queues.prepare(backend, queue_id_in); - - let error = 'error: { - let adapter = match self.hub.adapters.get(adapter_id) { - Ok(adapter) => adapter, - Err(_) => break 'error RequestDeviceError::InvalidAdapter, - }; - let (device, queue) = - match adapter.create_device_and_queue(desc, self.instance.flags, trace_path) { - Ok((device, queue)) => (device, queue), - Err(e) => break 'error e, - }; + let device_fid = self.hub.devices.prepare(device_id_in); + let queue_fid = self.hub.queues.prepare(queue_id_in); - let device_id = device_fid.assign(device); - resource_log!("Created Device {:?}", device_id); + let adapter = self.hub.adapters.get(adapter_id); + let (device, queue) = + adapter.create_device_and_queue(desc, self.instance.flags, trace_path)?; - let queue_id = queue_fid.assign(queue); - resource_log!("Created Queue {:?}", queue_id); + let device_id = device_fid.assign(device); + resource_log!("Created Device {:?}", device_id); - return (device_id, queue_id, None); - }; + let queue_id = queue_fid.assign(queue); + resource_log!("Created Queue {:?}", queue_id); - let device_id = device_fid.assign_error(); - let queue_id = queue_fid.assign_error(); - (device_id, queue_id, Some(error)) + Ok((device_id, queue_id)) } /// # Safety @@ -1001,40 +791,27 @@ impl Global { trace_path: Option<&std::path::Path>, device_id_in: Option, queue_id_in: Option, - ) -> (DeviceId, QueueId, Option) { + ) -> Result<(DeviceId, QueueId), RequestDeviceError> { profiling::scope!("Global::create_device_from_hal"); - let backend = adapter_id.backend(); - let devices_fid = self.hub.devices.prepare(backend, device_id_in); - let queues_fid = self.hub.queues.prepare(backend, queue_id_in); + let devices_fid = self.hub.devices.prepare(device_id_in); + let queues_fid = self.hub.queues.prepare(queue_id_in); - let error = 'error: { - let adapter = match self.hub.adapters.get(adapter_id) { - Ok(adapter) => adapter, - Err(_) => break 'error RequestDeviceError::InvalidAdapter, - }; - let (device, queue) = match adapter.create_device_and_queue_from_hal( - hal_device, - desc, - self.instance.flags, - trace_path, - ) { - Ok(device) => device, - Err(e) => break 'error e, - }; - - let device_id = devices_fid.assign(device); - resource_log!("Created Device {:?}", device_id); + let adapter = self.hub.adapters.get(adapter_id); + let (device, queue) = adapter.create_device_and_queue_from_hal( + hal_device, + desc, + self.instance.flags, + trace_path, + )?; - let queue_id = queues_fid.assign(queue); - resource_log!("Created Queue {:?}", queue_id); + let device_id = devices_fid.assign(device); + resource_log!("Created Device {:?}", device_id); - return (device_id, queue_id, None); - }; + let queue_id = queues_fid.assign(queue); + resource_log!("Created Queue {:?}", queue_id); - let device_id = devices_fid.assign_error(); - let queue_id = queues_fid.assign_error(); - (device_id, queue_id, Some(error)) + Ok((device_id, queue_id)) } } diff --git a/wgpu-core/src/lock/mod.rs b/wgpu-core/src/lock/mod.rs index a6593a062d..2927bf3aaf 100644 --- a/wgpu-core/src/lock/mod.rs +++ b/wgpu-core/src/lock/mod.rs @@ -9,17 +9,22 @@ //! checks to ensure that each thread acquires locks only in a //! specific order, to prevent deadlocks. //! +//! - The [`observing`] module defines lock types that record +//! `wgpu-core`'s lock acquisition activity to disk, for later +//! analysis by the `lock-analyzer` binary. +//! //! - The [`vanilla`] module defines lock types that are //! uninstrumented, no-overhead wrappers around the standard lock //! types. //! -//! (We plan to add more wrappers in the future.) -//! //! If the `wgpu_validate_locks` config is set (for example, with //! `RUSTFLAGS='--cfg wgpu_validate_locks'`), `wgpu-core` uses the //! [`ranked`] module's locks. We hope to make this the default for //! debug builds soon. //! +//! If the `observe_locks` feature is enabled, `wgpu-core` uses the +//! [`observing`] module's locks. +//! //! Otherwise, `wgpu-core` uses the [`vanilla`] module's locks. //! //! [`Mutex`]: parking_lot::Mutex @@ -31,11 +36,19 @@ pub mod rank; #[cfg_attr(not(wgpu_validate_locks), allow(dead_code))] mod ranked; -#[cfg_attr(wgpu_validate_locks, allow(dead_code))] +#[cfg(feature = "observe_locks")] +mod observing; + +#[cfg_attr(any(wgpu_validate_locks, feature = "observe_locks"), allow(dead_code))] mod vanilla; #[cfg(wgpu_validate_locks)] -pub use ranked::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use ranked as chosen; + +#[cfg(feature = "observe_locks")] +use observing as chosen; + +#[cfg(not(any(wgpu_validate_locks, feature = "observe_locks")))] +use vanilla as chosen; -#[cfg(not(wgpu_validate_locks))] -pub use vanilla::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; +pub use chosen::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; diff --git a/wgpu-core/src/lock/observing.rs b/wgpu-core/src/lock/observing.rs new file mode 100644 index 0000000000..afda1ad574 --- /dev/null +++ b/wgpu-core/src/lock/observing.rs @@ -0,0 +1,489 @@ +//! Lock types that observe lock acquisition order. +//! +//! This module's [`Mutex`] type is instrumented to observe the +//! nesting of `wgpu-core` lock acquisitions. Whenever `wgpu-core` +//! acquires one lock while it is already holding another, we note +//! that nesting pair. This tells us what the [`LockRank::followers`] +//! set for each lock would need to include to accommodate +//! `wgpu-core`'s observed behavior. +//! +//! When `wgpu-core`'s `observe_locks` feature is enabled, if the +//! `WGPU_CORE_LOCK_OBSERVE_DIR` environment variable is set to the +//! path of an existing directory, then every thread that acquires a +//! lock in `wgpu-core` will write its own log file to that directory. +//! You can then run the `wgpu` workspace's `lock-analyzer` binary to +//! read those files and summarize the results. The output from +//! `lock-analyzer` has the same form as the lock ranks given in +//! [`lock/rank.rs`]. +//! +//! If the `WGPU_CORE_LOCK_OBSERVE_DIR` environment variable is not +//! set, then no instrumentation takes place, and the locks behave +//! normally. +//! +//! To make sure we capture all acquisitions regardless of when the +//! program exits, each thread writes events directly to its log file +//! as they occur. A `write` system call is generally just a copy from +//! userspace into the kernel's buffer, so hopefully this approach +//! will still have tolerable performance. +//! +//! [`lock/rank.rs`]: ../../../src/wgpu_core/lock/rank.rs.html + +use crate::FastHashSet; + +use super::rank::{LockRank, LockRankSet}; +use std::{ + cell::RefCell, + fs::File, + panic::Location, + path::{Path, PathBuf}, +}; + +/// A `Mutex` instrumented for lock acquisition order observation. +/// +/// This is just a wrapper around a [`parking_lot::Mutex`], along with +/// its rank in the `wgpu_core` lock ordering. +/// +/// For details, see [the module documentation][self]. +pub struct Mutex { + inner: parking_lot::Mutex, + rank: LockRank, +} + +/// A guard produced by locking [`Mutex`]. +/// +/// This is just a wrapper around a [`parking_lot::MutexGuard`], along +/// with the state needed to track lock acquisition. +/// +/// For details, see [the module documentation][self]. +pub struct MutexGuard<'a, T> { + inner: parking_lot::MutexGuard<'a, T>, + _state: LockStateGuard, +} + +impl Mutex { + pub fn new(rank: LockRank, value: T) -> Mutex { + Mutex { + inner: parking_lot::Mutex::new(value), + rank, + } + } + + #[track_caller] + pub fn lock(&self) -> MutexGuard { + let saved = acquire(self.rank, Location::caller()); + MutexGuard { + inner: self.inner.lock(), + _state: LockStateGuard { saved }, + } + } +} + +impl<'a, T> MutexGuard<'a, T> { + pub fn try_map(s: Self, f: F) -> Result, ()> + where + F: FnOnce(&mut T) -> Option<&mut U>, + { + parking_lot::MutexGuard::try_map(s.inner, f).map_err(|_| ()) + } +} + +impl<'a, T> std::ops::Deref for MutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.inner.deref() + } +} + +impl<'a, T> std::ops::DerefMut for MutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner.deref_mut() + } +} + +impl std::fmt::Debug for Mutex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner.fmt(f) + } +} + +/// An `RwLock` instrumented for lock acquisition order observation. +/// +/// This is just a wrapper around a [`parking_lot::RwLock`], along with +/// its rank in the `wgpu_core` lock ordering. +/// +/// For details, see [the module documentation][self]. +pub struct RwLock { + inner: parking_lot::RwLock, + rank: LockRank, +} + +/// A read guard produced by locking [`RwLock`] for reading. +/// +/// This is just a wrapper around a [`parking_lot::RwLockReadGuard`], along with +/// the state needed to track lock acquisition. +/// +/// For details, see [the module documentation][self]. +pub struct RwLockReadGuard<'a, T> { + inner: parking_lot::RwLockReadGuard<'a, T>, + _state: LockStateGuard, +} + +/// A write guard produced by locking [`RwLock`] for writing. +/// +/// This is just a wrapper around a [`parking_lot::RwLockWriteGuard`], along +/// with the state needed to track lock acquisition. +/// +/// For details, see [the module documentation][self]. +pub struct RwLockWriteGuard<'a, T> { + inner: parking_lot::RwLockWriteGuard<'a, T>, + _state: LockStateGuard, +} + +impl RwLock { + pub fn new(rank: LockRank, value: T) -> RwLock { + RwLock { + inner: parking_lot::RwLock::new(value), + rank, + } + } + + #[track_caller] + pub fn read(&self) -> RwLockReadGuard { + let saved = acquire(self.rank, Location::caller()); + RwLockReadGuard { + inner: self.inner.read(), + _state: LockStateGuard { saved }, + } + } + + #[track_caller] + pub fn write(&self) -> RwLockWriteGuard { + let saved = acquire(self.rank, Location::caller()); + RwLockWriteGuard { + inner: self.inner.write(), + _state: LockStateGuard { saved }, + } + } +} + +impl<'a, T> RwLockWriteGuard<'a, T> { + pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> { + RwLockReadGuard { + inner: parking_lot::RwLockWriteGuard::downgrade(this.inner), + _state: this._state, + } + } +} + +impl std::fmt::Debug for RwLock { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner.fmt(f) + } +} + +impl<'a, T> std::ops::Deref for RwLockReadGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.inner.deref() + } +} + +impl<'a, T> std::ops::Deref for RwLockWriteGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.inner.deref() + } +} + +impl<'a, T> std::ops::DerefMut for RwLockWriteGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner.deref_mut() + } +} + +/// A container that restores a prior per-thread lock state when dropped. +/// +/// This type serves two purposes: +/// +/// - Operations like `RwLockWriteGuard::downgrade` would like to be able to +/// destructure lock guards and reassemble their pieces into new guards, but +/// if the guard type itself implements `Drop`, we can't destructure it +/// without unsafe code or pointless `Option`s whose state is almost always +/// statically known. +/// +/// - We can just implement `Drop` for this type once, and then use it in lock +/// guards, rather than implementing `Drop` separately for each guard type. +struct LockStateGuard { + /// The youngest lock that was already held when we acquired this + /// one, if any. + saved: Option, +} + +impl Drop for LockStateGuard { + fn drop(&mut self) { + release(self.saved) + } +} + +/// Check and record the acquisition of a lock with `new_rank`. +/// +/// Log the acquisition of a lock with `new_rank`, and +/// update the per-thread state accordingly. +/// +/// Return the `Option` state that must be restored when this lock is +/// released. +fn acquire(new_rank: LockRank, location: &'static Location<'static>) -> Option { + LOCK_STATE.with_borrow_mut(|state| match *state { + ThreadState::Disabled => None, + ThreadState::Initial => { + let Ok(dir) = std::env::var("WGPU_CORE_LOCK_OBSERVE_DIR") else { + *state = ThreadState::Disabled; + return None; + }; + + // Create the observation log file. + let mut log = ObservationLog::create(dir) + .expect("Failed to open lock observation file (does the dir exist?)"); + + // Log the full set of lock ranks, so that the analysis can even see + // locks that are only acquired in isolation. + for rank in LockRankSet::all().iter() { + log.write_rank(rank); + } + + // Update our state to reflect that we are logging acquisitions, and + // that we have acquired this lock. + *state = ThreadState::Enabled { + held_lock: Some(HeldLock { + rank: new_rank, + location, + }), + log, + }; + + // Since this is the first acquisition on this thread, we know that + // there is no prior lock held, and thus nothing to log yet. + None + } + ThreadState::Enabled { + ref mut held_lock, + ref mut log, + } => { + if let Some(ref held_lock) = held_lock { + log.write_acquisition(held_lock, new_rank, location); + } + + std::mem::replace( + held_lock, + Some(HeldLock { + rank: new_rank, + location, + }), + ) + } + }) +} + +/// Record the release of a lock whose saved state was `saved`. +fn release(saved: Option) { + LOCK_STATE.with_borrow_mut(|state| { + if let ThreadState::Enabled { + ref mut held_lock, .. + } = *state + { + *held_lock = saved; + } + }); +} + +thread_local! { + static LOCK_STATE: RefCell = const { RefCell::new(ThreadState::Initial) }; +} + +/// Thread-local state for lock observation. +enum ThreadState { + /// This thread hasn't yet checked the environment variable. + Initial, + + /// This thread checked the environment variable, and it was + /// unset, so this thread is not observing lock acquisitions. + Disabled, + + /// Lock observation is enabled for this thread. + Enabled { + held_lock: Option, + log: ObservationLog, + }, +} + +/// Information about a currently held lock. +#[derive(Debug, Copy, Clone)] +struct HeldLock { + /// The lock's rank. + rank: LockRank, + + /// Where we acquired the lock. + location: &'static Location<'static>, +} + +/// A log to which we can write observations of lock activity. +struct ObservationLog { + /// The file to which we are logging lock observations. + log_file: File, + + /// [`Location`]s we've seen so far. + /// + /// This is a hashset of raw pointers because raw pointers have + /// the [`Eq`] and [`Hash`] relations we want: the pointer value, not + /// the contents. There's no unsafe code in this module. + locations_seen: FastHashSet<*const Location<'static>>, + + /// Buffer for serializing events, retained for allocation reuse. + buffer: Vec, +} + +#[allow(trivial_casts)] +impl ObservationLog { + /// Create an observation log in `dir` for the current pid and thread. + fn create(dir: impl AsRef) -> Result { + let mut path = PathBuf::from(dir.as_ref()); + path.push(format!( + "locks-{}.{:?}.ron", + std::process::id(), + std::thread::current().id() + )); + let log_file = File::create(&path)?; + Ok(ObservationLog { + log_file, + locations_seen: FastHashSet::default(), + buffer: Vec::new(), + }) + } + + /// Record the acquisition of one lock while holding another. + /// + /// Log that we acquired a lock of `new_rank` at `new_location` while still + /// holding other locks, the most recently acquired of which has + /// `older_rank`. + fn write_acquisition( + &mut self, + older_lock: &HeldLock, + new_rank: LockRank, + new_location: &'static Location<'static>, + ) { + self.write_location(older_lock.location); + self.write_location(new_location); + self.write_action(&Action::Acquisition { + older_rank: older_lock.rank.bit.number(), + older_location: addr(older_lock.location), + newer_rank: new_rank.bit.number(), + newer_location: addr(new_location), + }); + } + + fn write_location(&mut self, location: &'static Location<'static>) { + if self.locations_seen.insert(location) { + self.write_action(&Action::Location { + address: addr(location), + file: location.file(), + line: location.line(), + column: location.column(), + }); + } + } + + fn write_rank(&mut self, rank: LockRankSet) { + self.write_action(&Action::Rank { + bit: rank.number(), + member_name: rank.member_name(), + const_name: rank.const_name(), + }); + } + + fn write_action(&mut self, action: &Action) { + use std::io::Write; + + self.buffer.clear(); + ron::ser::to_writer(&mut self.buffer, &action) + .expect("error serializing `lock::observing::Action`"); + self.buffer.push(b'\n'); + self.log_file + .write_all(&self.buffer) + .expect("error writing `lock::observing::Action`"); + } +} + +/// An action logged by a thread that is observing lock acquisition order. +/// +/// Each thread's log file is a sequence of these enums, serialized +/// using the [`ron`] crate, one action per line. +/// +/// Lock observation cannot assume that there will be any convenient +/// finalization point before the program exits, so in practice, +/// actions must be written immediately when they occur. This means we +/// can't, say, accumulate tables and write them out when they're +/// complete. The `lock-analyzer` binary is then responsible for +/// consolidating the data into a single table of observed transitions. +#[derive(serde::Serialize)] +enum Action { + /// A location that we will refer to in later actions. + /// + /// We write one of these events the first time we see a + /// particular `Location`. Treating this as a separate action + /// simply lets us avoid repeating the content over and over + /// again in every [`Acquisition`] action. + /// + /// [`Acquisition`]: Action::Acquisition + Location { + address: usize, + file: &'static str, + line: u32, + column: u32, + }, + + /// A lock rank that we will refer to in later actions. + /// + /// We write out one these events for every lock rank at the + /// beginning of each thread's log file. Treating this as a + /// separate action simply lets us avoid repeating the names over + /// and over again in every [`Acquisition`] action. + /// + /// [`Acquisition`]: Action::Acquisition + Rank { + bit: u32, + member_name: &'static str, + const_name: &'static str, + }, + + /// An attempt to acquire a lock while holding another lock. + Acquisition { + /// The number of the already acquired lock's rank. + older_rank: u32, + + /// The source position at which we acquired it. Specifically, + /// its `Location`'s address, as an integer. + older_location: usize, + + /// The number of the rank of the lock we are acquiring. + newer_rank: u32, + + /// The source position at which we are acquiring it. + /// Specifically, its `Location`'s address, as an integer. + newer_location: usize, + }, +} + +impl LockRankSet { + /// Return the number of this rank's first member. + fn number(self) -> u32 { + self.bits().trailing_zeros() + } +} + +/// Convenience for `std::ptr::from_ref(t) as usize`. +fn addr(t: &T) -> usize { + std::ptr::from_ref(t) as usize +} diff --git a/wgpu-core/src/lock/rank.rs b/wgpu-core/src/lock/rank.rs index 8b55b27d8f..87b977d62a 100644 --- a/wgpu-core/src/lock/rank.rs +++ b/wgpu-core/src/lock/rank.rs @@ -63,7 +63,7 @@ macro_rules! define_lock_ranks { } impl LockRankSet { - pub fn name(self) -> &'static str { + pub fn member_name(self) -> &'static str { match self { $( LockRankSet:: $name => $member, @@ -71,6 +71,16 @@ macro_rules! define_lock_ranks { _ => "", } } + + #[cfg_attr(not(feature = "observe_locks"), allow(dead_code))] + pub fn const_name(self) -> &'static str { + match self { + $( + LockRankSet:: $name => stringify!($name), + )* + _ => "", + } + } } $( diff --git a/wgpu-core/src/lock/ranked.rs b/wgpu-core/src/lock/ranked.rs index 13301f86fc..c3aedb1b08 100644 --- a/wgpu-core/src/lock/ranked.rs +++ b/wgpu-core/src/lock/ranked.rs @@ -63,9 +63,7 @@ use std::{cell::Cell, panic::Location}; /// This is just a wrapper around a [`parking_lot::Mutex`], along with /// its rank in the `wgpu_core` lock ordering. /// -/// For details, see [the module documentation][mod]. -/// -/// [mod]: crate::lock::ranked +/// For details, see [the module documentation][self]. pub struct Mutex { inner: parking_lot::Mutex, rank: LockRank, @@ -76,9 +74,7 @@ pub struct Mutex { /// This is just a wrapper around a [`parking_lot::MutexGuard`], along /// with the state needed to track lock acquisition. /// -/// For details, see [the module documentation][mod]. -/// -/// [mod]: crate::lock::ranked +/// For details, see [the module documentation][self]. pub struct MutexGuard<'a, T> { inner: parking_lot::MutexGuard<'a, T>, saved: LockStateGuard, @@ -144,12 +140,12 @@ fn acquire(new_rank: LockRank, location: &'static Location<'static>) -> LockStat last locked {:<35} at {}\n\ now locking {:<35} at {}\n\ Locking {} after locking {} is not permitted.", - last_rank.bit.name(), + last_rank.bit.member_name(), last_location, - new_rank.bit.name(), + new_rank.bit.member_name(), location, - new_rank.bit.name(), - last_rank.bit.name(), + new_rank.bit.member_name(), + last_rank.bit.member_name(), ); } LOCK_STATE.set(LockState { @@ -220,9 +216,7 @@ impl std::fmt::Debug for Mutex { /// This is just a wrapper around a [`parking_lot::RwLock`], along with /// its rank in the `wgpu_core` lock ordering. /// -/// For details, see [the module documentation][mod]. -/// -/// [mod]: crate::lock::ranked +/// For details, see [the module documentation][self]. pub struct RwLock { inner: parking_lot::RwLock, rank: LockRank, @@ -233,9 +227,7 @@ pub struct RwLock { /// This is just a wrapper around a [`parking_lot::RwLockReadGuard`], along with /// the state needed to track lock acquisition. /// -/// For details, see [the module documentation][mod]. -/// -/// [mod]: crate::lock::ranked +/// For details, see [the module documentation][self]. pub struct RwLockReadGuard<'a, T> { inner: parking_lot::RwLockReadGuard<'a, T>, saved: LockStateGuard, @@ -246,9 +238,7 @@ pub struct RwLockReadGuard<'a, T> { /// This is just a wrapper around a [`parking_lot::RwLockWriteGuard`], along /// with the state needed to track lock acquisition. /// -/// For details, see [the module documentation][mod]. -/// -/// [mod]: crate::lock::ranked +/// For details, see [the module documentation][self]. pub struct RwLockWriteGuard<'a, T> { inner: parking_lot::RwLockWriteGuard<'a, T>, saved: LockStateGuard, diff --git a/wgpu-core/src/lock/vanilla.rs b/wgpu-core/src/lock/vanilla.rs index 9a35b6d9d8..51e472b118 100644 --- a/wgpu-core/src/lock/vanilla.rs +++ b/wgpu-core/src/lock/vanilla.rs @@ -30,6 +30,15 @@ impl Mutex { } } +impl<'a, T> MutexGuard<'a, T> { + pub fn try_map(s: Self, f: F) -> Result, ()> + where + F: FnOnce(&mut T) -> Option<&mut U>, + { + parking_lot::MutexGuard::try_map(s.0, f).map_err(|_| ()) + } +} + impl<'a, T> std::ops::Deref for MutexGuard<'a, T> { type Target = T; diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index db1c1ba76a..08e7167db6 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -4,7 +4,7 @@ use crate::{ command::ColorAttachmentError, device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext}, id::{PipelineCacheId, PipelineLayoutId, ShaderModuleId}, - resource::{Labeled, TrackingData}, + resource::{InvalidResourceError, Labeled, TrackingData}, resource_log, validation, Label, }; use arrayvec::ArrayVec; @@ -222,10 +222,6 @@ pub struct ResolvedComputePipelineDescriptor<'a> { pub enum CreateComputePipelineError { #[error(transparent)] Device(#[from] DeviceError), - #[error("Pipeline layout is invalid")] - InvalidLayout, - #[error("Cache is invalid")] - InvalidCache, #[error("Unable to derive an implicit layout")] Implicit(#[from] ImplicitLayoutError), #[error("Error matching shader requirements against the pipeline")] @@ -236,6 +232,8 @@ pub enum CreateComputePipelineError { PipelineConstants(String), #[error(transparent)] MissingDownlevelFlags(#[from] MissingDownlevelFlags), + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } #[derive(Debug)] @@ -286,16 +284,6 @@ pub enum CreatePipelineCacheError { Internal(String), } -impl From for CreatePipelineCacheError { - fn from(value: hal::PipelineCacheError) -> Self { - match value { - hal::PipelineCacheError::Device(device) => { - CreatePipelineCacheError::Device(device.into()) - } - } - } -} - #[derive(Debug)] pub struct PipelineCache { pub(crate) raw: ManuallyDrop>, @@ -477,10 +465,6 @@ pub enum CreateRenderPipelineError { ColorAttachment(#[from] ColorAttachmentError), #[error(transparent)] Device(#[from] DeviceError), - #[error("Pipeline layout is invalid")] - InvalidLayout, - #[error("Pipeline cache is invalid")] - InvalidCache, #[error("Unable to derive an implicit layout")] Implicit(#[from] ImplicitLayoutError), #[error("Color state [{0}] is invalid")] @@ -550,6 +534,8 @@ pub enum CreateRenderPipelineError { "but no render target for the pipeline was specified." ))] NoTargetSpecified, + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } bitflags::bitflags! { diff --git a/wgpu-core/src/pipeline_cache.rs b/wgpu-core/src/pipeline_cache.rs index b88fc21dda..e506d2cd5b 100644 --- a/wgpu-core/src/pipeline_cache.rs +++ b/wgpu-core/src/pipeline_cache.rs @@ -1,7 +1,9 @@ +use std::mem::size_of; + use thiserror::Error; use wgt::AdapterInfo; -pub const HEADER_LENGTH: usize = std::mem::size_of::(); +pub const HEADER_LENGTH: usize = size_of::(); #[derive(Debug, PartialEq, Eq, Clone, Error)] #[non_exhaustive] @@ -112,7 +114,7 @@ pub fn add_cache_header( const MAGIC: [u8; 8] = *b"WGPUPLCH"; const HEADER_VERSION: u32 = 1; -const ABI: u32 = std::mem::size_of::<*const ()>() as u32; +const ABI: u32 = size_of::<*const ()>() as u32; /// The value used to fill [`PipelineCacheHeader::hash_space`] /// @@ -179,10 +181,7 @@ impl PipelineCacheHeader { let data_size = reader.read_u64()?; let data_hash = reader.read_u64()?; - assert_eq!( - reader.total_read, - std::mem::size_of::() - ); + assert_eq!(reader.total_read, size_of::()); Some(( PipelineCacheHeader { diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 697156b35f..c9d0124bf4 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -122,10 +122,7 @@ impl Global { let hub = &self.hub; - let surface = self - .surfaces - .get(surface_id) - .map_err(|_| SurfaceError::Invalid)?; + let surface = self.surfaces.get(surface_id); let (device, config) = if let Some(ref present) = *surface.presentation.lock() { present.device.check_is_valid()?; @@ -134,7 +131,7 @@ impl Global { return Err(SurfaceError::NotConfigured); }; - let fid = hub.textures.prepare(device.backend(), texture_id_in); + let fid = hub.textures.prepare(texture_id_in); #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -179,7 +176,7 @@ impl Global { let clear_view_desc = hal::TextureViewDescriptor { label: hal_label( Some("(wgpu internal) clear surface texture view"), - self.instance.flags, + device.instance_flags, ), format: config.format, dimension: wgt::TextureViewDimension::D2, @@ -191,7 +188,7 @@ impl Global { .raw() .create_texture_view(ast.texture.as_ref().borrow(), &clear_view_desc) } - .map_err(DeviceError::from)?; + .map_err(|e| device.handle_hal_error(e))?; let mut presentation = surface.presentation.lock(); let present = presentation.as_mut().unwrap(); @@ -218,7 +215,7 @@ impl Global { .textures .insert_single(&texture, hal::TextureUses::UNINITIALIZED); - let id = fid.assign(texture); + let id = fid.assign(resource::Fallible::Valid(texture)); if present.acquired_texture.is_some() { return Err(SurfaceError::AlreadyAcquired); @@ -238,7 +235,7 @@ impl Global { match err { hal::SurfaceError::Lost => Status::Lost, hal::SurfaceError::Device(err) => { - return Err(DeviceError::from(err).into()); + return Err(device.handle_hal_error(err).into()); } hal::SurfaceError::Outdated => Status::Outdated, hal::SurfaceError::Other(msg) => { @@ -257,10 +254,7 @@ impl Global { let hub = &self.hub; - let surface = self - .surfaces - .get(surface_id) - .map_err(|_| SurfaceError::Invalid)?; + let surface = self.surfaces.get(surface_id); let mut presentation = surface.presentation.lock(); let present = match presentation.as_mut() { @@ -286,8 +280,8 @@ impl Global { // The texture ID got added to the device tracker by `submit()`, // and now we are moving it away. - let texture = hub.textures.unregister(texture_id); - if let Some(texture) = texture { + let texture = hub.textures.remove(texture_id).get(); + if let Ok(texture) = texture { device .trackers .lock() @@ -315,7 +309,9 @@ impl Global { Ok(()) => Ok(Status::Good), Err(err) => match err { hal::SurfaceError::Lost => Ok(Status::Lost), - hal::SurfaceError::Device(err) => Err(SurfaceError::from(DeviceError::from(err))), + hal::SurfaceError::Device(err) => { + Err(SurfaceError::from(device.handle_hal_error(err))) + } hal::SurfaceError::Outdated => Ok(Status::Outdated), hal::SurfaceError::Other(msg) => { log::error!("acquire error: {}", msg); @@ -330,10 +326,7 @@ impl Global { let hub = &self.hub; - let surface = self - .surfaces - .get(surface_id) - .map_err(|_| SurfaceError::Invalid)?; + let surface = self.surfaces.get(surface_id); let mut presentation = surface.presentation.lock(); let present = match presentation.as_mut() { Some(present) => present, @@ -357,9 +350,9 @@ impl Global { // The texture ID got added to the device tracker by `submit()`, // and now we are moving it away. - let texture = hub.textures.unregister(texture_id); + let texture = hub.textures.remove(texture_id).get(); - if let Some(texture) = texture { + if let Ok(texture) = texture { device .trackers .lock() diff --git a/wgpu-core/src/registry.rs b/wgpu-core/src/registry.rs index fa7e0def6c..b3349235e9 100644 --- a/wgpu-core/src/registry.rs +++ b/wgpu-core/src/registry.rs @@ -1,10 +1,10 @@ -use std::sync::Arc; +use std::{mem::size_of, sync::Arc}; use crate::{ id::Id, identity::IdentityManager, lock::{rank, RwLock, RwLockReadGuard, RwLockWriteGuard}, - storage::{Element, InvalidId, Storage, StorageItem}, + storage::{Element, Storage, StorageItem}, }; #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] @@ -12,7 +12,6 @@ pub struct RegistryReport { pub num_allocated: usize, pub num_kept_from_user: usize, pub num_released_from_user: usize, - pub num_error: usize, pub element_size: usize, } @@ -56,63 +55,43 @@ pub(crate) struct FutureId<'a, T: StorageItem> { } impl FutureId<'_, T> { - #[allow(dead_code)] pub fn id(&self) -> Id { self.id } - pub fn into_id(self) -> Id { - self.id - } - /// Assign a new resource to this ID. /// /// Registers it with the registry. - pub fn assign(self, value: Arc) -> Id { + pub fn assign(self, value: T) -> Id { let mut data = self.data.write(); data.insert(self.id, value); self.id } - - pub fn assign_error(self) -> Id { - self.data.write().insert_error(self.id); - self.id - } } impl Registry { - pub(crate) fn prepare( - &self, - backend: wgt::Backend, - id_in: Option>, - ) -> FutureId { + pub(crate) fn prepare(&self, id_in: Option>) -> FutureId { FutureId { id: match id_in { Some(id_in) => { self.identity.mark_as_used(id_in); id_in } - None => self.identity.process(backend), + None => self.identity.process(), }, data: &self.storage, } } - pub(crate) fn get(&self, id: Id) -> Result, InvalidId> { - self.read().get_owned(id) - } + #[track_caller] pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage> { self.storage.read() } + #[track_caller] pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage> { self.storage.write() } - pub(crate) fn force_replace_with_error(&self, id: Id) { - let mut storage = self.storage.write(); - storage.remove(id); - storage.insert_error(id); - } - pub(crate) fn unregister(&self, id: Id) -> Option> { + pub(crate) fn remove(&self, id: Id) -> T { let value = self.storage.write().remove(id); // This needs to happen *after* removing it from the storage, to maintain the // invariant that `self.identity` only contains ids which are actually available @@ -125,7 +104,7 @@ impl Registry { pub(crate) fn generate_report(&self) -> RegistryReport { let storage = self.storage.read(); let mut report = RegistryReport { - element_size: std::mem::size_of::(), + element_size: size_of::(), ..Default::default() }; report.num_allocated = self.identity.values.lock().count(); @@ -133,13 +112,18 @@ impl Registry { match *element { Element::Occupied(..) => report.num_kept_from_user += 1, Element::Vacant => report.num_released_from_user += 1, - Element::Error(_) => report.num_error += 1, } } report } } +impl Registry { + pub(crate) fn get(&self, id: Id) -> T { + self.read().get(id) + } +} + #[cfg(test)] mod tests { use std::sync::Arc; @@ -166,9 +150,9 @@ mod tests { s.spawn(|| { for _ in 0..1000 { let value = Arc::new(TestData); - let new_id = registry.prepare(wgt::Backend::Empty, None); + let new_id = registry.prepare(None); let id = new_id.assign(value); - registry.unregister(id); + registry.remove(id); } }); } diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 83e45c7f2c..5f24eb31e7 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -108,8 +108,8 @@ pub(crate) trait ParentDevice: Labeled { } } - fn same_device(&self, device: &Arc) -> Result<(), DeviceError> { - if Arc::ptr_eq(self.device(), device) { + fn same_device(&self, device: &Device) -> Result<(), DeviceError> { + if std::ptr::eq(&**self.device(), device) { Ok(()) } else { Err(DeviceError::DeviceMismatch(Box::new(DeviceMismatch { @@ -307,7 +307,7 @@ impl BufferMapCallback { let status = match result { Ok(()) => BufferMapAsyncStatus::Success, Err(BufferAccessError::Device(_)) => BufferMapAsyncStatus::ContextLost, - Err(BufferAccessError::InvalidBufferId(_)) + Err(BufferAccessError::InvalidResource(_)) | Err(BufferAccessError::DestroyedResource(_)) => BufferMapAsyncStatus::Invalid, Err(BufferAccessError::AlreadyMapped) => BufferMapAsyncStatus::AlreadyMapped, Err(BufferAccessError::MapAlreadyPending) => { @@ -326,7 +326,9 @@ impl BufferMapCallback { | Err(BufferAccessError::NegativeRange { .. }) => { BufferMapAsyncStatus::InvalidRange } - Err(_) => BufferMapAsyncStatus::Error, + Err(BufferAccessError::Failed) + | Err(BufferAccessError::NotMapped) + | Err(BufferAccessError::MapAborted) => BufferMapAsyncStatus::Error, }; (inner.callback)(status, inner.user_data); @@ -349,8 +351,6 @@ pub enum BufferAccessError { Device(#[from] DeviceError), #[error("Buffer map failed")] Failed, - #[error("BufferId {0:?} is invalid")] - InvalidBufferId(BufferId), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), #[error("Buffer is already mapped")] @@ -388,6 +388,8 @@ pub enum BufferAccessError { }, #[error("Buffer map aborted")] MapAborted, + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } #[derive(Clone, Debug, Error)] @@ -412,6 +414,45 @@ pub struct MissingTextureUsageError { #[error("{0} has been destroyed")] pub struct DestroyedResourceError(pub ResourceErrorIdent); +#[derive(Clone, Debug, Error)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[error("{0} is invalid")] +pub struct InvalidResourceError(pub ResourceErrorIdent); + +pub(crate) enum Fallible { + Valid(Arc), + Invalid(Arc), +} + +impl Fallible { + pub fn get(self) -> Result, InvalidResourceError> { + match self { + Fallible::Valid(v) => Ok(v), + Fallible::Invalid(label) => Err(InvalidResourceError(ResourceErrorIdent { + r#type: Cow::Borrowed(T::TYPE), + label: (*label).clone(), + })), + } + } +} + +impl Clone for Fallible { + fn clone(&self) -> Self { + match self { + Self::Valid(v) => Self::Valid(v.clone()), + Self::Invalid(l) => Self::Invalid(l.clone()), + } + } +} + +impl ResourceType for Fallible { + const TYPE: &'static str = T::TYPE; +} + +impl crate::storage::StorageItem for Fallible { + type Marker = T::Marker; +} + pub type BufferAccessResult = Result<(), BufferAccessError>; #[derive(Debug)] @@ -834,8 +875,10 @@ impl StagingBuffer { memory_flags: hal::MemoryFlags::TRANSIENT, }; - let raw = unsafe { device.raw().create_buffer(&stage_desc)? }; - let mapping = unsafe { device.raw().map_buffer(raw.as_ref(), 0..size.get()) }?; + let raw = unsafe { device.raw().create_buffer(&stage_desc) } + .map_err(|e| device.handle_hal_error(e))?; + let mapping = unsafe { device.raw().map_buffer(raw.as_ref(), 0..size.get()) } + .map_err(|e| device.handle_hal_error(e))?; let staging_buffer = StagingBuffer { raw, @@ -957,7 +1000,7 @@ impl ScratchBuffer { usage: BufferUses::ACCELERATION_STRUCTURE_SCRATCH | BufferUses::MAP_WRITE, memory_flags: hal::MemoryFlags::empty(), }) - .map_err(crate::device::DeviceError::from)? + .map_err(crate::device::DeviceError::from_hal)? }; Ok(Self { raw: ManuallyDrop::new(raw), @@ -1054,7 +1097,7 @@ impl Texture { if init { TextureInitTracker::new(desc.mip_level_count, desc.array_layer_count()) } else { - TextureInitTracker::new(0, 0) + TextureInitTracker::new(desc.mip_level_count, 0) }, ), full_range: TextureSelector { @@ -1240,7 +1283,7 @@ impl Global { let hub = &self.hub; - if let Ok(buffer) = hub.buffers.get(id) { + if let Ok(buffer) = hub.buffers.get(id).get() { let snatch_guard = buffer.device.snatchable_lock.read(); let hal_buffer = buffer .raw(&snatch_guard) @@ -1263,7 +1306,7 @@ impl Global { let hub = &self.hub; - if let Ok(texture) = hub.textures.get(id) { + if let Ok(texture) = hub.textures.get(id).get() { let snatch_guard = texture.device.snatchable_lock.read(); let hal_texture = texture.raw(&snatch_guard); let hal_texture = hal_texture @@ -1287,7 +1330,7 @@ impl Global { let hub = &self.hub; - if let Ok(texture_view) = hub.texture_views.get(id) { + if let Ok(texture_view) = hub.texture_views.get(id).get() { let snatch_guard = texture_view.device.snatchable_lock.read(); let hal_texture_view = texture_view.raw(&snatch_guard); let hal_texture_view = hal_texture_view @@ -1310,11 +1353,8 @@ impl Global { profiling::scope!("Adapter::as_hal"); let hub = &self.hub; - let adapter = hub.adapters.get(id).ok(); - let hal_adapter = adapter - .as_ref() - .map(|adapter| &adapter.raw.adapter) - .and_then(|adapter| adapter.as_any().downcast_ref()); + let adapter = hub.adapters.get(id); + let hal_adapter = adapter.raw.adapter.as_any().downcast_ref(); hal_adapter_callback(hal_adapter) } @@ -1329,12 +1369,8 @@ impl Global { ) -> R { profiling::scope!("Device::as_hal"); - let hub = &self.hub; - let device = hub.devices.get(id).ok(); - let hal_device = device - .as_ref() - .map(|device| device.raw()) - .and_then(|device| device.as_any().downcast_ref()); + let device = self.hub.devices.get(id); + let hal_device = device.raw().as_any().downcast_ref(); hal_device_callback(hal_device) } @@ -1349,14 +1385,9 @@ impl Global { ) -> R { profiling::scope!("Device::fence_as_hal"); - let hub = &self.hub; - - if let Ok(device) = hub.devices.get(id) { - let fence = device.fence.read(); - hal_fence_callback(fence.as_any().downcast_ref()) - } else { - hal_fence_callback(None) - } + let device = self.hub.devices.get(id); + let fence = device.fence.read(); + hal_fence_callback(fence.as_any().downcast_ref()) } /// # Safety @@ -1368,10 +1399,9 @@ impl Global { ) -> R { profiling::scope!("Surface::as_hal"); - let surface = self.surfaces.get(id).ok(); + let surface = self.surfaces.get(id); let hal_surface = surface - .as_ref() - .and_then(|surface| surface.raw(A::VARIANT)) + .raw(A::VARIANT) .and_then(|surface| surface.as_any().downcast_ref()); hal_surface_callback(hal_surface) @@ -1393,12 +1423,13 @@ impl Global { let hub = &self.hub; - if let Ok(cmd_buf) = hub.command_buffers.get(id.into_command_buffer_id()) { - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); + let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id()); + let cmd_buf_data = cmd_buf.try_get(); + + if let Ok(mut cmd_buf_data) = cmd_buf_data { let cmd_buf_raw = cmd_buf_data .encoder - .open() + .open(&cmd_buf.device) .ok() .and_then(|encoder| encoder.as_any_mut().downcast_mut()); hal_command_encoder_callback(cmd_buf_raw) @@ -1656,8 +1687,6 @@ impl TextureView { pub enum CreateTextureViewError { #[error(transparent)] Device(#[from] DeviceError), - #[error("TextureId {0:?} is invalid")] - InvalidTextureId(TextureId), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), #[error("Not enough memory left to create texture view")] @@ -1700,6 +1729,8 @@ pub enum CreateTextureViewError { texture: wgt::TextureFormat, view: wgt::TextureFormat, }, + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } #[derive(Clone, Debug, Error)] @@ -1872,10 +1903,10 @@ impl QuerySet { #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum DestroyError { - #[error("Resource is invalid")] - Invalid, #[error("Resource is already destroyed")] AlreadyDestroyed, + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } pub type BlasDescriptor<'a> = wgt::CreateBlasDescriptor>; diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index c5e91eedd4..5930748759 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -1,33 +1,35 @@ use std::sync::Arc; -use wgt::Backend; - use crate::id::{Id, Marker}; use crate::resource::ResourceType; use crate::{Epoch, Index}; /// An entry in a `Storage::map` table. #[derive(Debug)] -pub(crate) enum Element { +pub(crate) enum Element +where + T: StorageItem, +{ /// There are no live ids with this index. Vacant, /// There is one live id with this index, allocated at the given /// epoch. - Occupied(Arc, Epoch), - - /// Like `Occupied`, but an error occurred when creating the - /// resource. - Error(Epoch), + Occupied(T, Epoch), } -#[derive(Clone, Debug)] -pub(crate) struct InvalidId; - pub(crate) trait StorageItem: ResourceType { type Marker: Marker; } +impl ResourceType for Arc { + const TYPE: &'static str = T::TYPE; +} + +impl StorageItem for Arc { + type Marker = T::Marker; +} + #[macro_export] macro_rules! impl_storage_item { ($ty:ident) => { @@ -70,34 +72,13 @@ impl Storage where T: StorageItem, { - /// Get a reference to an item behind a potentially invalid ID. - /// Panics if there is an epoch mismatch, or the entry is empty. - pub(crate) fn get(&self, id: Id) -> Result<&Arc, InvalidId> { - let (index, epoch, _) = id.unzip(); - let (result, storage_epoch) = match self.map.get(index as usize) { - Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch), - None | Some(&Element::Vacant) => panic!("{}[{:?}] does not exist", self.kind, id), - Some(&Element::Error(epoch)) => (Err(InvalidId), epoch), - }; - assert_eq!( - epoch, storage_epoch, - "{}[{:?}] is no longer alive", - self.kind, id - ); - result - } - - /// Get an owned reference to an item behind a potentially invalid ID. - /// Panics if there is an epoch mismatch, or the entry is empty. - pub(crate) fn get_owned(&self, id: Id) -> Result, InvalidId> { - Ok(Arc::clone(self.get(id)?)) - } - - fn insert_impl(&mut self, index: usize, epoch: Epoch, element: Element) { + pub(crate) fn insert(&mut self, id: Id, value: T) { + let (index, epoch) = id.unzip(); + let index = index as usize; if index >= self.map.len() { self.map.resize_with(index + 1, || Element::Vacant); } - match std::mem::replace(&mut self.map[index], element) { + match std::mem::replace(&mut self.map[index], Element::Occupied(value, epoch)) { Element::Vacant => {} Element::Occupied(_, storage_epoch) => { assert_ne!( @@ -107,58 +88,27 @@ where T::TYPE ); } - Element::Error(storage_epoch) => { - assert_ne!( - epoch, - storage_epoch, - "Index {index:?} of {} is already occupied with Error", - T::TYPE - ); - } - } - } - - pub(crate) fn insert(&mut self, id: Id, value: Arc) { - let (index, epoch, _backend) = id.unzip(); - self.insert_impl(index as usize, epoch, Element::Occupied(value, epoch)) - } - - pub(crate) fn insert_error(&mut self, id: Id) { - let (index, epoch, _) = id.unzip(); - self.insert_impl(index as usize, epoch, Element::Error(epoch)) - } - - pub(crate) fn replace_with_error(&mut self, id: Id) -> Result, InvalidId> { - let (index, epoch, _) = id.unzip(); - match std::mem::replace(&mut self.map[index as usize], Element::Error(epoch)) { - Element::Vacant => panic!("Cannot access vacant resource"), - Element::Occupied(value, storage_epoch) => { - assert_eq!(epoch, storage_epoch); - Ok(value) - } - _ => Err(InvalidId), } } - pub(crate) fn remove(&mut self, id: Id) -> Option> { - let (index, epoch, _) = id.unzip(); + pub(crate) fn remove(&mut self, id: Id) -> T { + let (index, epoch) = id.unzip(); match std::mem::replace(&mut self.map[index as usize], Element::Vacant) { Element::Occupied(value, storage_epoch) => { assert_eq!(epoch, storage_epoch); - Some(value) + value } - Element::Error(_) => None, Element::Vacant => panic!("Cannot remove a vacant resource"), } } - pub(crate) fn iter(&self, backend: Backend) -> impl Iterator, &Arc)> { + pub(crate) fn iter(&self) -> impl Iterator, &T)> { self.map .iter() .enumerate() .filter_map(move |(index, x)| match *x { Element::Occupied(ref value, storage_epoch) => { - Some((Id::zip(index as Index, storage_epoch, backend), value)) + Some((Id::zip(index as Index, storage_epoch), value)) } _ => None, }) @@ -168,3 +118,24 @@ where self.map.len() } } + +impl Storage +where + T: StorageItem + Clone, +{ + /// Get an owned reference to an item. + /// Panics if there is an epoch mismatch, the entry is empty or in error. + pub(crate) fn get(&self, id: Id) -> T { + let (index, epoch) = id.unzip(); + let (result, storage_epoch) = match self.map.get(index as usize) { + Some(&Element::Occupied(ref v, epoch)) => (v.clone(), epoch), + None | Some(&Element::Vacant) => panic!("{}[{:?}] does not exist", self.kind, id), + }; + assert_eq!( + epoch, storage_epoch, + "{}[{:?}] is no longer alive", + self.kind, id + ); + result + } +} diff --git a/wgpu-core/src/track/texture.rs b/wgpu-core/src/track/texture.rs index 1c74bffd97..60c2238961 100644 --- a/wgpu-core/src/track/texture.rs +++ b/wgpu-core/src/track/texture.rs @@ -442,10 +442,9 @@ impl TextureTracker { let transitions = self .temp .drain(..) - .map(|pending| { + .inspect(|pending| { let tex = unsafe { self.metadata.get_resource_unchecked(pending.id as _) }; textures.push(tex.inner.get(snatch_guard)); - pending }) .collect(); (transitions, textures) diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 3488e981b5..13cf443d48 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -1,4 +1,4 @@ -use crate::{device::bgl, FastHashMap, FastHashSet}; +use crate::{device::bgl, resource::InvalidResourceError, FastHashMap, FastHashSet}; use arrayvec::ArrayVec; use std::{collections::hash_map::Entry, fmt}; use thiserror::Error; @@ -201,8 +201,6 @@ pub enum InputError { #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum StageError { - #[error("Shader module is invalid")] - InvalidModule, #[error( "Shader entry point's workgroup size {current:?} ({current_total} total invocations) must be less or equal to the per-dimension limit {limit:?} and the total invocation limit {total}" )] @@ -242,6 +240,8 @@ pub enum StageError { but no entry point was specified" )] MultipleEntryPointsFound, + #[error(transparent)] + InvalidResource(#[from] InvalidResourceError), } fn map_storage_format_to_naga(format: wgt::TextureFormat) -> Option { @@ -276,7 +276,7 @@ fn map_storage_format_to_naga(format: wgt::TextureFormat) -> Option Sf::Rgb10a2Uint, Tf::Rgb10a2Unorm => Sf::Rgb10a2Unorm, - Tf::Rg11b10UFloat => Sf::Rg11b10UFloat, + Tf::Rg11b10Ufloat => Sf::Rg11b10Ufloat, Tf::Rg32Uint => Sf::Rg32Uint, Tf::Rg32Sint => Sf::Rg32Sint, @@ -332,7 +332,7 @@ fn map_storage_format_from_naga(format: naga::StorageFormat) -> wgt::TextureForm Sf::Rgb10a2Uint => Tf::Rgb10a2Uint, Sf::Rgb10a2Unorm => Tf::Rgb10a2Unorm, - Sf::Rg11b10UFloat => Tf::Rg11b10UFloat, + Sf::Rg11b10Ufloat => Tf::Rg11b10Ufloat, Sf::Rg32Uint => Tf::Rg32Uint, Sf::Rg32Sint => Tf::Rg32Sint, @@ -661,7 +661,7 @@ impl NumericType { Tf::Rgba8Sint | Tf::Rgba16Sint | Tf::Rgba32Sint => { (NumericDimension::Vector(Vs::Quad), Scalar::I32) } - Tf::Rg11b10UFloat => (NumericDimension::Vector(Vs::Tri), Scalar::F32), + Tf::Rg11b10Ufloat => (NumericDimension::Vector(Vs::Tri), Scalar::F32), Tf::Stencil8 | Tf::Depth16Unorm | Tf::Depth32Float diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index eedd027bfe..d3a05f0790 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -71,22 +71,25 @@ gles = [ ## Has no effect if not targeting Windows. dx12 = [ # DX12 is only available on Windows, therefore request HLSL output also only if we target Windows. - "naga/hlsl-out-if-target-windows", - "dep:d3d12", "dep:bit-set", "dep:libloading", "dep:range-alloc", - "winapi/std", - "winapi/winbase", - "winapi/d3d12", - "winapi/d3d12shader", - "winapi/d3d12sdklayers", - "winapi/dxgi1_6", - "winapi/errhandlingapi", + "dep:windows-core", + "gpu-allocator/d3d12", + "naga/hlsl-out-if-target-windows", + "windows/Win32_Graphics_Direct3D_Fxc", + "windows/Win32_Graphics_Direct3D_Dxc", + "windows/Win32_Graphics_Direct3D", + "windows/Win32_Graphics_Direct3D12", + "windows/Win32_Graphics_DirectComposition", + "windows/Win32_Graphics_Dxgi_Common", + "windows/Win32_Security", + "windows/Win32_System_Diagnostics_Debug", + "windows/Win32_System_Kernel", + "windows/Win32_System_Performance", + "windows/Win32_System_Threading", + "windows/Win32_UI_WindowsAndMessaging", ] -# TODO: This is a separate feature until Mozilla okays windows-rs, see https://github.com/gfx-rs/wgpu/issues/3207 for the tracking issue. -windows_rs = ["dep:gpu-allocator"] -dxc_shader_compiler = ["dep:hassle-rs"] renderdoc = ["dep:libloading", "dep:renderdoc-sys"] fragile-send-sync-non-atomic-wasm = ["wgt/fragile-send-sync-non-atomic-wasm"] # Panic when running into an out-of-memory error (for debugging purposes). @@ -153,21 +156,12 @@ windows = { workspace = true, optional = true } bit-set = { workspace = true, optional = true } range-alloc = { workspace = true, optional = true } gpu-allocator = { workspace = true, optional = true } -hassle-rs = { workspace = true, optional = true } +# For core macros. This crate is also reexported as windows::core. +windows-core = { workspace = true, optional = true } # backend: Gles glutin_wgl_sys = { workspace = true, optional = true } -winapi = { version = "0.3", features = [ - "profileapi", - "windef", - "winuser", - "dcomp", -] } -d3d12 = { path = "../d3d12/", version = "22.0.0", optional = true, features = [ - "libloading", -] } - [target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies] # backend: Metal block = { workspace = true, optional = true } @@ -212,5 +206,8 @@ env_logger.workspace = true glam.workspace = true # for ray-traced-triangle example winit.workspace = true # for "halmark" example -[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] -glutin.workspace = true # for "gles" example +[target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dev-dependencies] +glutin-winit = { workspace = true, features = ["egl", "wgl", "wayland", "x11"] } # for "raw-gles" example +glutin = { workspace = true, features = ["egl", "wgl", "wayland", "x11"] } # for "raw-gles" example +rwh_05 = { version = "0.5", package = "raw-window-handle" } # temporary compatibility for glutin-winit in "raw-gles" example +winit = { workspace = true, features = ["rwh_05"] } # for "raw-gles" example diff --git a/wgpu-hal/README.md b/wgpu-hal/README.md index bb5556b3d2..4f048eb1bc 100644 --- a/wgpu-hal/README.md +++ b/wgpu-hal/README.md @@ -89,7 +89,7 @@ platform graphics APIs: [`ash`]: https://crates.io/crates/ash [MoltenVK]: https://github.com/KhronosGroup/MoltenVK [`metal`]: https://crates.io/crates/metal -[`d3d12`]: ahttps://crates.io/crates/d3d12 +[`d3d12`]: https://crates.io/crates/d3d12 ## Secondary backends diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index dabcea418a..8ab7f1cb47 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -14,7 +14,9 @@ use winit::{ use std::{ borrow::{Borrow, Cow}, - iter, mem, ptr, + iter, + mem::size_of, + ptr, time::Instant, }; @@ -193,7 +195,7 @@ impl Example { ty: wgt::BindingType::Buffer { ty: wgt::BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: wgt::BufferSize::new(mem::size_of::() as _), + min_binding_size: wgt::BufferSize::new(size_of::() as _), }, count: None, }, @@ -228,7 +230,7 @@ impl Example { ty: wgt::BindingType::Buffer { ty: wgt::BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: wgt::BufferSize::new(mem::size_of::() as _), + min_binding_size: wgt::BufferSize::new(size_of::() as _), }, count: None, }], @@ -394,7 +396,7 @@ impl Example { let global_buffer_desc = hal::BufferDescriptor { label: Some("global"), - size: mem::size_of::() as wgt::BufferAddress, + size: size_of::() as wgt::BufferAddress, usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::UNIFORM, memory_flags: hal::MemoryFlags::PREFER_COHERENT, }; @@ -406,7 +408,7 @@ impl Example { ptr::copy_nonoverlapping( &globals as *const Globals as *const u8, mapping.ptr.as_ptr(), - mem::size_of::(), + size_of::(), ); device.unmap_buffer(&buffer); assert!(mapping.is_coherent); @@ -414,7 +416,7 @@ impl Example { }; let local_alignment = wgt::math::align_to( - mem::size_of::() as u32, + size_of::() as u32, capabilities.limits.min_uniform_buffer_offset_alignment, ); let local_buffer_desc = hal::BufferDescriptor { @@ -476,7 +478,7 @@ impl Example { let local_buffer_binding = hal::BufferBinding { buffer: &local_buffer, offset: 0, - size: wgt::BufferSize::new(mem::size_of::() as _), + size: wgt::BufferSize::new(size_of::() as _), }; let local_group_desc = hal::BindGroupDescriptor { label: Some("local"), diff --git a/wgpu-hal/examples/raw-gles.rs b/wgpu-hal/examples/raw-gles.rs index 06df610658..2743ce9b82 100644 --- a/wgpu-hal/examples/raw-gles.rs +++ b/wgpu-hal/examples/raw-gles.rs @@ -10,61 +10,198 @@ extern crate wgpu_hal as hal; -#[cfg(not(any(windows, target_arch = "wasm32")))] +#[cfg(not(any(target_arch = "wasm32", target_os = "ios")))] fn main() { + use std::{ffi::CString, num::NonZeroU32}; + + use glutin::{ + config::GlConfig as _, + context::{NotCurrentGlContext as _, PossiblyCurrentGlContext as _, Version}, + display::{GetGlDisplay as _, GlDisplay as _}, + surface::GlSurface as _, + }; + use glutin_winit::GlWindow as _; + use rwh_05::HasRawWindowHandle as _; + env_logger::init(); println!("Initializing external GL context"); - let event_loop = glutin::event_loop::EventLoop::new(); - let window_builder = glutin::window::WindowBuilder::new(); - let gl_context = unsafe { - glutin::ContextBuilder::new() - .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0))) - .build_windowed(window_builder, &event_loop) - .unwrap() - .make_current() - .unwrap() - }; - let inner_size = gl_context.window().inner_size(); + let event_loop = winit::event_loop::EventLoop::new().unwrap(); + // Only Windows requires the window to be present before creating the display. + // Other platforms don't really need one. + let window_builder = cfg!(windows).then(|| { + winit::window::WindowBuilder::new() + .with_title("WGPU raw GLES example (press Escape to exit)") + }); - println!("Hooking up to wgpu-hal"); - let exposed = unsafe { - ::Adapter::new_external(|name| { - gl_context.get_proc_address(name) - }) + // The template will match only the configurations supporting rendering + // to Windows. + let template = glutin::config::ConfigTemplateBuilder::new(); + + let display_builder = glutin_winit::DisplayBuilder::new().with_window_builder(window_builder); + + // Find the config with the maximum number of samples, so our triangle will be + // smooth. + pub fn gl_config_picker( + configs: Box + '_>, + ) -> glutin::config::Config { + configs + .reduce(|accum, config| { + if config.num_samples() > accum.num_samples() { + config + } else { + accum + } + }) + .expect("Failed to find a matching config") } - .expect("GL adapter can't be initialized"); - fill_screen(&exposed, inner_size.width, inner_size.height); - - println!("Showing the window"); - gl_context.swap_buffers().unwrap(); - - event_loop.run(move |event, _, control_flow| { - use glutin::{ - event::{Event, KeyboardInput, VirtualKeyCode, WindowEvent}, - event_loop::ControlFlow, - }; - *control_flow = ControlFlow::Wait; - - match event { - Event::LoopDestroyed => (), - Event::WindowEvent { - event: - WindowEvent::CloseRequested - | WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(VirtualKeyCode::Escape), - .. - }, - .. - }, - .. - } => *control_flow = ControlFlow::Exit, - _ => (), - } + let (mut window, gl_config) = display_builder + .build(&event_loop, template, gl_config_picker) + .expect("Failed to build window and config from display"); + + println!("Picked a config with {} samples", gl_config.num_samples()); + + let raw_window_handle = window.as_ref().map(|window| window.raw_window_handle()); + + // XXX The display could be obtained from any object created by it, so we can + // query it from the config. + let gl_display = gl_config.display(); + + // Glutin tries to create an OpenGL context by default. Force it to use any version of GLES. + let context_attributes = glutin::context::ContextAttributesBuilder::new() + // WGPU expects GLES 3.0+. + .with_context_api(glutin::context::ContextApi::Gles(Some(Version::new(3, 0)))) + .build(raw_window_handle); + + let mut not_current_gl_context = Some(unsafe { + gl_display + .create_context(&gl_config, &context_attributes) + .expect("failed to create context") }); + + let mut state = None; + + // Only needs to be loaded once + let mut exposed = None; + + event_loop + .run(move |event, window_target| { + use winit::{ + event::{Event, KeyEvent, WindowEvent}, + event_loop::ControlFlow, + keyboard::{Key, NamedKey}, + }; + window_target.set_control_flow(ControlFlow::Wait); + + match event { + // Event::LoopExiting => (), + Event::WindowEvent { + window_id: _, + event: + WindowEvent::CloseRequested + | WindowEvent::KeyboardInput { + event: + KeyEvent { + logical_key: Key::Named(NamedKey::Escape), + .. + }, + .. + }, + } => window_target.exit(), + Event::Resumed => { + let window = window.take().unwrap_or_else(|| { + let window_builder = winit::window::WindowBuilder::new() + .with_title("WGPU raw GLES example (press Escape to exit)"); + glutin_winit::finalize_window(window_target, window_builder, &gl_config) + .unwrap() + }); + + let attrs = window.build_surface_attributes(Default::default()); + let gl_surface = unsafe { + gl_config + .display() + .create_window_surface(&gl_config, &attrs) + .expect("Cannot create GL WindowSurface") + }; + + // Make it current. + let gl_context = not_current_gl_context + .take() + .unwrap() + .make_current(&gl_surface) + .expect("GL context cannot be made current with WindowSurface"); + + // The context needs to be current for the Renderer to set up shaders and + // buffers. It also performs function loading, which needs a current context on + // WGL. + println!("Hooking up to wgpu-hal"); + exposed.get_or_insert_with(|| { + unsafe { + ::Adapter::new_external(|name| { + // XXX: On WGL this should only be called after the context was made current + gl_config + .display() + .get_proc_address(&CString::new(name).expect(name)) + }) + } + .expect("GL adapter can't be initialized") + }); + + assert!(state.replace((gl_context, gl_surface, window)).is_none()); + } + Event::Suspended => { + // This event is only raised on Android, where the backing NativeWindow for a GL + // Surface can appear and disappear at any moment. + println!("Android window removed"); + + // Destroy the GL Surface and un-current the GL Context before ndk-glue releases + // the window back to the system. + let (gl_context, ..) = state.take().unwrap(); + assert!(not_current_gl_context + .replace(gl_context.make_not_current().unwrap()) + .is_none()); + } + Event::WindowEvent { + window_id: _, + event: WindowEvent::Resized(size), + } => { + if size.width != 0 && size.height != 0 { + // Some platforms like EGL require resizing GL surface to update the size + // Notable platforms here are Wayland and macOS, other don't require it + // and the function is no-op, but it's wise to resize it for portability + // reasons. + if let Some((gl_context, gl_surface, _)) = &state { + gl_surface.resize( + gl_context, + NonZeroU32::new(size.width).unwrap(), + NonZeroU32::new(size.height).unwrap(), + ); + // XXX: If there's a state for fill_screen(), this would need to be updated too. + } + } + } + Event::WindowEvent { + window_id: _, + event: WindowEvent::RedrawRequested, + } => { + if let (Some(exposed), Some((gl_context, gl_surface, window))) = + (&exposed, &state) + { + let inner_size = window.inner_size(); + + fill_screen(exposed, inner_size.width, inner_size.height); + + println!("Showing the window"); + gl_surface + .swap_buffers(gl_context) + .expect("Failed to swap buffers"); + } + } + _ => (), + } + }) + .expect("Couldn't run event loop"); } #[cfg(target_os = "emscripten")] @@ -117,10 +254,18 @@ fn main() { fill_screen(&exposed, 640, 400); } -#[cfg(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten"))))] -fn main() {} +#[cfg(any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_os = "ios" +))] +fn main() { + eprintln!("This example is not supported on Windows and non-emscripten wasm32") +} -#[cfg(any(not(any(windows, target_arch = "wasm32")), target_os = "emscripten"))] +#[cfg(not(any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_os = "ios" +)))] fn fill_screen(exposed: &hal::ExposedAdapter, width: u32, height: u32) { use hal::{Adapter as _, CommandEncoder as _, Device as _, Queue as _}; diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index b1aceeb101..dd91843734 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -8,7 +8,9 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use glam::{Affine3A, Mat4, Vec3}; use std::{ borrow::{Borrow, Cow}, - iter, mem, ptr, + iter, + mem::size_of, + ptr, time::Instant, }; use winit::window::WindowButtons; @@ -203,7 +205,7 @@ struct Example { uniform_buffer: A::Buffer, pipeline_layout: A::PipelineLayout, vertices_buffer: A::Buffer, - indices_buffer: A::Buffer, + indices_buffer: Option, texture: A::Texture, instances: [AccelerationStructureInstance; 3], instances_buffer: A::Buffer, @@ -215,6 +217,18 @@ struct Example { impl Example { fn init(window: &winit::window::Window) -> Result> { + let mut index_buffer = false; + + for arg in std::env::args() { + if arg == "index_buffer" { + index_buffer = true; + } + } + + if index_buffer { + log::info!("using index buffer") + } + let instance_desc = hal::InstanceDescriptor { name: "example", flags: wgt::InstanceFlags::default(), @@ -304,7 +318,7 @@ impl Example { ty: wgt::BindingType::Buffer { ty: wgt::BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: wgt::BufferSize::new(mem::size_of::() as _), + min_binding_size: wgt::BufferSize::new(size_of::() as _), }, count: None, }, @@ -418,29 +432,34 @@ impl Example { vertices_buffer }; - let indices_buffer = unsafe { - let indices_buffer = device - .create_buffer(&hal::BufferDescriptor { - label: Some("indices buffer"), - size: indices_size_in_bytes as u64, - usage: hal::BufferUses::MAP_WRITE - | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, - memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, - }) - .unwrap(); - - let mapping = device - .map_buffer(&indices_buffer, 0..indices_size_in_bytes as u64) - .unwrap(); - ptr::copy_nonoverlapping( - indices.as_ptr() as *const u8, - mapping.ptr.as_ptr(), - indices_size_in_bytes, - ); - device.unmap_buffer(&indices_buffer); - assert!(mapping.is_coherent); + let indices_buffer = if index_buffer { + unsafe { + let indices_buffer = device + .create_buffer(&hal::BufferDescriptor { + label: Some("indices buffer"), + size: indices_size_in_bytes as u64, + usage: hal::BufferUses::MAP_WRITE + | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, + memory_flags: hal::MemoryFlags::TRANSIENT + | hal::MemoryFlags::PREFER_COHERENT, + }) + .unwrap(); - indices_buffer + let mapping = device + .map_buffer(&indices_buffer, 0..indices_size_in_bytes as u64) + .unwrap(); + ptr::copy_nonoverlapping( + indices.as_ptr() as *const u8, + mapping.ptr.as_ptr(), + indices_size_in_bytes, + ); + device.unmap_buffer(&indices_buffer); + assert!(mapping.is_coherent); + + Some((indices_buffer, indices.len())) + } + } else { + None }; let blas_triangles = vec![hal::AccelerationStructureTriangles { @@ -449,12 +468,15 @@ impl Example { vertex_format: wgt::VertexFormat::Float32x3, vertex_count: vertices.len() as u32, vertex_stride: 3 * 4, - indices: Some(hal::AccelerationStructureTriangleIndices { - buffer: Some(&indices_buffer), - format: wgt::IndexFormat::Uint32, - offset: 0, - count: indices.len() as u32, + indices: indices_buffer.as_ref().map(|(buf, len)| { + hal::AccelerationStructureTriangleIndices { + buffer: Some(buf), + format: wgt::IndexFormat::Uint32, + offset: 0, + count: *len as u32, + } }), + transform: None, flags: hal::AccelerationStructureGeometryFlags::OPAQUE, }]; @@ -516,7 +538,7 @@ impl Example { } }; - let uniforms_size = std::mem::size_of::(); + let uniforms_size = size_of::(); let uniform_buffer = unsafe { let uniform_buffer = device @@ -657,8 +679,7 @@ impl Example { ), ]; - let instances_buffer_size = - instances.len() * std::mem::size_of::(); + let instances_buffer_size = instances.len() * size_of::(); let instances_buffer = unsafe { let instances_buffer = device @@ -799,7 +820,7 @@ impl Example { tlas, scratch_buffer, time: 0.0, - indices_buffer, + indices_buffer: indices_buffer.map(|(buf, _)| buf), vertices_buffer, uniform_buffer, texture_view, @@ -828,7 +849,7 @@ impl Example { }; let instances_buffer_size = - self.instances.len() * std::mem::size_of::(); + self.instances.len() * size_of::(); let tlas_flags = hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE | hal::AccelerationStructureBuildFlags::ALLOW_UPDATE; @@ -1025,7 +1046,9 @@ impl Example { self.device.destroy_bind_group(self.bind_group); self.device.destroy_buffer(self.scratch_buffer); self.device.destroy_buffer(self.instances_buffer); - self.device.destroy_buffer(self.indices_buffer); + if let Some(buffer) = self.indices_buffer { + self.device.destroy_buffer(buffer); + } self.device.destroy_buffer(self.vertices_buffer); self.device.destroy_buffer(self.uniform_buffer); self.device.destroy_acceleration_structure(self.tlas); diff --git a/wgpu-hal/src/auxil/dxgi/conv.rs b/wgpu-hal/src/auxil/dxgi/conv.rs index d84e082df1..878dab39e9 100644 --- a/wgpu-hal/src/auxil/dxgi/conv.rs +++ b/wgpu-hal/src/auxil/dxgi/conv.rs @@ -1,5 +1,6 @@ use std::{ffi::OsString, os::windows::ffi::OsStringExt}; -use winapi::shared::dxgiformat; + +use windows::Win32::Graphics::Dxgi; // Helper to convert DXGI adapter name to a normal string pub fn map_adapter_name(name: [u16; 128]) -> String { @@ -8,9 +9,11 @@ pub fn map_adapter_name(name: [u16; 128]) -> String { name.to_string_lossy().into_owned() } -pub fn map_texture_format_failable(format: wgt::TextureFormat) -> Option { +pub fn map_texture_format_failable( + format: wgt::TextureFormat, +) -> Option { use wgt::TextureFormat as Tf; - use winapi::shared::dxgiformat::*; + use Dxgi::Common::*; Some(match format { Tf::R8Unorm => DXGI_FORMAT_R8_UNORM, @@ -44,7 +47,7 @@ pub fn map_texture_format_failable(format: wgt::TextureFormat) -> Option DXGI_FORMAT_R9G9B9E5_SHAREDEXP, Tf::Rgb10a2Uint => DXGI_FORMAT_R10G10B10A2_UINT, Tf::Rgb10a2Unorm => DXGI_FORMAT_R10G10B10A2_UNORM, - Tf::Rg11b10UFloat => DXGI_FORMAT_R11G11B10_FLOAT, + Tf::Rg11b10Ufloat => DXGI_FORMAT_R11G11B10_FLOAT, Tf::Rg32Uint => DXGI_FORMAT_R32G32_UINT, Tf::Rg32Sint => DXGI_FORMAT_R32G32_SINT, Tf::Rg32Float => DXGI_FORMAT_R32G32_FLOAT, @@ -94,7 +97,7 @@ pub fn map_texture_format_failable(format: wgt::TextureFormat) -> Option dxgiformat::DXGI_FORMAT { +pub fn map_texture_format(format: wgt::TextureFormat) -> Dxgi::Common::DXGI_FORMAT { match map_texture_format_failable(format) { Some(f) => f, None => unreachable!(), @@ -103,10 +106,10 @@ pub fn map_texture_format(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT // Note: DXGI doesn't allow sRGB format on the swapchain, // but creating RTV of swapchain buffers with sRGB works. -pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT { +pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> Dxgi::Common::DXGI_FORMAT { match format { - wgt::TextureFormat::Bgra8UnormSrgb => dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, - wgt::TextureFormat::Rgba8UnormSrgb => dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM, + wgt::TextureFormat::Bgra8UnormSrgb => Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM, + wgt::TextureFormat::Rgba8UnormSrgb => Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM, _ => map_texture_format(format), } } @@ -116,29 +119,29 @@ pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> dxgiformat::DXGI pub fn map_texture_format_for_srv_uav( format: wgt::TextureFormat, aspect: crate::FormatAspects, -) -> Option { +) -> Option { Some(match (format, aspect) { (wgt::TextureFormat::Depth16Unorm, crate::FormatAspects::DEPTH) => { - dxgiformat::DXGI_FORMAT_R16_UNORM + Dxgi::Common::DXGI_FORMAT_R16_UNORM } (wgt::TextureFormat::Depth32Float, crate::FormatAspects::DEPTH) => { - dxgiformat::DXGI_FORMAT_R32_FLOAT + Dxgi::Common::DXGI_FORMAT_R32_FLOAT } (wgt::TextureFormat::Depth32FloatStencil8, crate::FormatAspects::DEPTH) => { - dxgiformat::DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS + Dxgi::Common::DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS } ( wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8, crate::FormatAspects::DEPTH, - ) => dxgiformat::DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + ) => Dxgi::Common::DXGI_FORMAT_R24_UNORM_X8_TYPELESS, (wgt::TextureFormat::Depth32FloatStencil8, crate::FormatAspects::STENCIL) => { - dxgiformat::DXGI_FORMAT_X32_TYPELESS_G8X24_UINT + Dxgi::Common::DXGI_FORMAT_X32_TYPELESS_G8X24_UINT } ( wgt::TextureFormat::Stencil8 | wgt::TextureFormat::Depth24PlusStencil8, crate::FormatAspects::STENCIL, - ) => dxgiformat::DXGI_FORMAT_X24_TYPELESS_G8_UINT, + ) => Dxgi::Common::DXGI_FORMAT_X24_TYPELESS_G8_UINT, (_, crate::FormatAspects::DEPTH) | (_, crate::FormatAspects::STENCIL) @@ -152,22 +155,22 @@ pub fn map_texture_format_for_srv_uav( pub fn map_texture_format_for_copy( format: wgt::TextureFormat, aspect: crate::FormatAspects, -) -> Option { +) -> Option { Some(match (format, aspect) { (wgt::TextureFormat::Depth16Unorm, crate::FormatAspects::DEPTH) => { - dxgiformat::DXGI_FORMAT_R16_UNORM + Dxgi::Common::DXGI_FORMAT_R16_UNORM } ( wgt::TextureFormat::Depth32Float | wgt::TextureFormat::Depth32FloatStencil8, crate::FormatAspects::DEPTH, - ) => dxgiformat::DXGI_FORMAT_R32_FLOAT, + ) => Dxgi::Common::DXGI_FORMAT_R32_FLOAT, ( wgt::TextureFormat::Stencil8 | wgt::TextureFormat::Depth24PlusStencil8 | wgt::TextureFormat::Depth32FloatStencil8, crate::FormatAspects::STENCIL, - ) => dxgiformat::DXGI_FORMAT_R8_UINT, + ) => Dxgi::Common::DXGI_FORMAT_R8_UINT, (format, crate::FormatAspects::COLOR) => map_texture_format(format), @@ -180,9 +183,9 @@ pub fn map_texture_format_for_resource( usage: crate::TextureUses, has_view_formats: bool, casting_fully_typed_format_supported: bool, -) -> dxgiformat::DXGI_FORMAT { +) -> Dxgi::Common::DXGI_FORMAT { use wgt::TextureFormat as Tf; - use winapi::shared::dxgiformat::*; + use Dxgi::Common::*; if casting_fully_typed_format_supported { map_texture_format(format) @@ -219,16 +222,16 @@ pub fn map_texture_format_for_resource( } } -pub fn map_index_format(format: wgt::IndexFormat) -> dxgiformat::DXGI_FORMAT { +pub fn map_index_format(format: wgt::IndexFormat) -> Dxgi::Common::DXGI_FORMAT { match format { - wgt::IndexFormat::Uint16 => dxgiformat::DXGI_FORMAT_R16_UINT, - wgt::IndexFormat::Uint32 => dxgiformat::DXGI_FORMAT_R32_UINT, + wgt::IndexFormat::Uint16 => Dxgi::Common::DXGI_FORMAT_R16_UINT, + wgt::IndexFormat::Uint32 => Dxgi::Common::DXGI_FORMAT_R32_UINT, } } -pub fn map_vertex_format(format: wgt::VertexFormat) -> dxgiformat::DXGI_FORMAT { +pub fn map_vertex_format(format: wgt::VertexFormat) -> Dxgi::Common::DXGI_FORMAT { use wgt::VertexFormat as Vf; - use winapi::shared::dxgiformat::*; + use Dxgi::Common::*; match format { Vf::Unorm8x2 => DXGI_FORMAT_R8G8_UNORM, @@ -266,6 +269,6 @@ pub fn map_vertex_format(format: wgt::VertexFormat) -> dxgiformat::DXGI_FORMAT { } } -pub fn map_acomposite_alpha_mode(_mode: wgt::CompositeAlphaMode) -> d3d12::AlphaMode { - d3d12::AlphaMode::Ignore +pub fn map_acomposite_alpha_mode(_mode: wgt::CompositeAlphaMode) -> Dxgi::Common::DXGI_ALPHA_MODE { + Dxgi::Common::DXGI_ALPHA_MODE_IGNORE } diff --git a/wgpu-hal/src/auxil/dxgi/exception.rs b/wgpu-hal/src/auxil/dxgi/exception.rs index 70db8b2d0d..c3d655c6e5 100644 --- a/wgpu-hal/src/auxil/dxgi/exception.rs +++ b/wgpu-hal/src/auxil/dxgi/exception.rs @@ -1,10 +1,7 @@ use std::{borrow::Cow, slice}; use parking_lot::{lock_api::RawMutex, Mutex}; -use winapi::{ - um::{errhandlingapi, winnt}, - vc::excpt, -}; +use windows::Win32::{Foundation, System::Diagnostics::Debug}; // This is a mutex as opposed to an atomic as we need to completely // lock everyone out until we have registered or unregistered the @@ -17,9 +14,7 @@ static EXCEPTION_HANDLER_COUNT: Mutex = Mutex::const_new(parking_lot::Raw pub fn register_exception_handler() { let mut count_guard = EXCEPTION_HANDLER_COUNT.lock(); if *count_guard == 0 { - unsafe { - errhandlingapi::AddVectoredExceptionHandler(0, Some(output_debug_string_handler)) - }; + unsafe { Debug::AddVectoredExceptionHandler(0, Some(output_debug_string_handler)) }; } *count_guard += 1; } @@ -27,9 +22,7 @@ pub fn register_exception_handler() { pub fn unregister_exception_handler() { let mut count_guard = EXCEPTION_HANDLER_COUNT.lock(); if *count_guard == 1 { - unsafe { - errhandlingapi::RemoveVectoredExceptionHandler(output_debug_string_handler as *mut _) - }; + unsafe { Debug::RemoveVectoredExceptionHandler(output_debug_string_handler as *mut _) }; } *count_guard -= 1; } @@ -43,34 +36,34 @@ const MESSAGE_PREFIXES: &[(&str, log::Level)] = &[ ]; unsafe extern "system" fn output_debug_string_handler( - exception_info: *mut winnt::EXCEPTION_POINTERS, + exception_info: *mut Debug::EXCEPTION_POINTERS, ) -> i32 { // See https://stackoverflow.com/a/41480827 let record = unsafe { &*(*exception_info).ExceptionRecord }; if record.NumberParameters != 2 { - return excpt::EXCEPTION_CONTINUE_SEARCH; + return Debug::EXCEPTION_CONTINUE_SEARCH; } let message = match record.ExceptionCode { - winnt::DBG_PRINTEXCEPTION_C => String::from_utf8_lossy(unsafe { + Foundation::DBG_PRINTEXCEPTION_C => String::from_utf8_lossy(unsafe { slice::from_raw_parts( record.ExceptionInformation[1] as *const u8, record.ExceptionInformation[0], ) }), - winnt::DBG_PRINTEXCEPTION_WIDE_C => Cow::Owned(String::from_utf16_lossy(unsafe { + Foundation::DBG_PRINTEXCEPTION_WIDE_C => Cow::Owned(String::from_utf16_lossy(unsafe { slice::from_raw_parts( record.ExceptionInformation[1] as *const u16, record.ExceptionInformation[0], ) })), - _ => return excpt::EXCEPTION_CONTINUE_SEARCH, + _ => return Debug::EXCEPTION_CONTINUE_SEARCH, }; let message = match message.strip_prefix("D3D12 ") { Some(msg) => msg .trim_end_matches("\n\0") .trim_end_matches("[ STATE_CREATION WARNING #0: UNKNOWN]"), - None => return excpt::EXCEPTION_CONTINUE_SEARCH, + None => return Debug::EXCEPTION_CONTINUE_SEARCH, }; let (message, level) = match MESSAGE_PREFIXES @@ -84,12 +77,12 @@ unsafe extern "system" fn output_debug_string_handler( if level == log::Level::Warn && message.contains("#82") { // This is are useless spammy warnings (#820, #821): // "The application did not pass any clear value to resource creation" - return excpt::EXCEPTION_CONTINUE_SEARCH; + return Debug::EXCEPTION_CONTINUE_SEARCH; } if level == log::Level::Warn && message.contains("DRAW_EMPTY_SCISSOR_RECTANGLE") { // This is normal, WebGPU allows passing empty scissor rectangles. - return excpt::EXCEPTION_CONTINUE_SEARCH; + return Debug::EXCEPTION_CONTINUE_SEARCH; } let _ = std::panic::catch_unwind(|| { @@ -101,5 +94,5 @@ unsafe extern "system" fn output_debug_string_handler( crate::VALIDATION_CANARY.add(message.to_string()); } - excpt::EXCEPTION_CONTINUE_EXECUTION + Debug::EXCEPTION_CONTINUE_EXECUTION } diff --git a/wgpu-hal/src/auxil/dxgi/factory.rs b/wgpu-hal/src/auxil/dxgi/factory.rs index 38fdd17c89..4b71abda37 100644 --- a/wgpu-hal/src/auxil/dxgi/factory.rs +++ b/wgpu-hal/src/auxil/dxgi/factory.rs @@ -1,20 +1,13 @@ -use winapi::{ - shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, winerror}, - Interface, -}; +use std::ops::Deref; -use super::result::HResult as _; +use windows::{core::Interface as _, Win32::Graphics::Dxgi}; -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum DxgiFactoryType { - Factory2, - Factory4, - Factory6, -} +use crate::dx12::DxgiLib; + +// We can rely on the presence of DXGI 1.4 since D3D12 requires WDDM 2.0, Windows 10 (1507), and so does DXGI 1.4. -fn should_keep_adapter(adapter: &dxgi::IDXGIAdapter1) -> bool { - let mut desc = unsafe { std::mem::zeroed() }; - unsafe { adapter.GetDesc1(&mut desc) }; +fn should_keep_adapter(adapter: &Dxgi::IDXGIAdapter1) -> bool { + let desc = unsafe { adapter.GetDesc1() }.unwrap(); // The Intel Haswell family of iGPUs had support for the D3D12 API but it was later // removed due to a security vulnerability. @@ -40,8 +33,10 @@ fn should_keep_adapter(adapter: &dxgi::IDXGIAdapter1) -> bool { // which is lying about being an integrated card. This is so that programs // that ignore software adapters will actually run on headless/gpu-less machines. // - // We don't want that and discorage that kind of filtering anyway, so we skip the integrated WARP. - if desc.VendorId == 5140 && (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) == 0 { + // We don't want that and discourage that kind of filtering anyway, so we skip the integrated WARP. + if desc.VendorId == 5140 + && Dxgi::DXGI_ADAPTER_FLAG(desc.Flags as i32).contains(Dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) + { let adapter_name = super::conv::map_adapter_name(desc.Description); if adapter_name.contains("Microsoft Basic Render Driver") { return false; @@ -51,211 +46,123 @@ fn should_keep_adapter(adapter: &dxgi::IDXGIAdapter1) -> bool { true } -pub fn enumerate_adapters(factory: d3d12::DxgiFactory) -> Vec { +pub enum DxgiAdapter { + /// Provided by DXGI 1.4 + Adapter3(Dxgi::IDXGIAdapter3), + /// Provided by DXGI 1.6 + Adapter4(Dxgi::IDXGIAdapter4), +} + +impl Deref for DxgiAdapter { + type Target = Dxgi::IDXGIAdapter3; + + fn deref(&self) -> &Self::Target { + match self { + DxgiAdapter::Adapter3(a) => a, + DxgiAdapter::Adapter4(a) => a, + } + } +} + +pub fn enumerate_adapters(factory: DxgiFactory) -> Vec { let mut adapters = Vec::with_capacity(8); for cur_index in 0.. { - if let Some(factory6) = factory.as_factory6() { - profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference"); - // We're already at dxgi1.6, we can grab IDXGIAdapter4 directly - let mut adapter4 = d3d12::ComPtr::::null(); - let hr = unsafe { - factory6.EnumAdapterByGpuPreference( - cur_index, - dxgi1_6::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, - &dxgi1_6::IDXGIAdapter4::uuidof(), - adapter4.mut_void(), - ) - }; - - if hr == winerror::DXGI_ERROR_NOT_FOUND { - break; - } - if let Err(err) = hr.into_result() { - log::error!("Failed enumerating adapters: {}", err); + profiling::scope!("IDXGIFactory1::EnumAdapters1"); + let adapter1: Dxgi::IDXGIAdapter1 = match unsafe { factory.EnumAdapters1(cur_index) } { + Ok(a) => a, + Err(e) if e.code() == Dxgi::DXGI_ERROR_NOT_FOUND => break, + Err(e) => { + log::error!("Failed enumerating adapters: {}", e); break; } + }; - if !should_keep_adapter(&adapter4) { - continue; - } - - adapters.push(d3d12::DxgiAdapter::Adapter4(adapter4)); + if !should_keep_adapter(&adapter1) { continue; } - profiling::scope!("IDXGIFactory1::EnumAdapters1"); - let mut adapter1 = d3d12::ComPtr::::null(); - let hr = unsafe { factory.EnumAdapters1(cur_index, adapter1.mut_self()) }; - - if hr == winerror::DXGI_ERROR_NOT_FOUND { - break; - } - if let Err(err) = hr.into_result() { - log::error!("Failed enumerating adapters: {}", err); - break; + if let Ok(adapter4) = adapter1.cast::() { + adapters.push(DxgiAdapter::Adapter4(adapter4)); + } else { + let adapter3 = adapter1.cast::().unwrap(); + adapters.push(DxgiAdapter::Adapter3(adapter3)); } + } - if !should_keep_adapter(&adapter1) { - continue; - } + adapters +} - // Do the most aggressive casts first, skipping Adapter4 as we definitely don't have dxgi1_6. +#[derive(Clone, Debug)] +pub enum DxgiFactory { + /// Provided by DXGI 1.4 + Factory4(Dxgi::IDXGIFactory4), + /// Provided by DXGI 1.5 + Factory5(Dxgi::IDXGIFactory5), + /// Provided by DXGI 1.6 + Factory6(Dxgi::IDXGIFactory6), +} - // Adapter1 -> Adapter3 - unsafe { - match adapter1.cast::().into_result() { - Ok(adapter3) => { - adapters.push(d3d12::DxgiAdapter::Adapter3(adapter3)); - continue; - } - Err(err) => { - log::warn!("Failed casting Adapter1 to Adapter3: {}", err); - } - } - } +impl Deref for DxgiFactory { + type Target = Dxgi::IDXGIFactory4; - // Adapter1 -> Adapter2 - unsafe { - match adapter1.cast::().into_result() { - Ok(adapter2) => { - adapters.push(d3d12::DxgiAdapter::Adapter2(adapter2)); - continue; - } - Err(err) => { - log::warn!("Failed casting Adapter1 to Adapter2: {}", err); - } - } + fn deref(&self) -> &Self::Target { + match self { + DxgiFactory::Factory4(f) => f, + DxgiFactory::Factory5(f) => f, + DxgiFactory::Factory6(f) => f, } - - adapters.push(d3d12::DxgiAdapter::Adapter1(adapter1)); } +} - adapters +impl DxgiFactory { + pub fn as_factory5(&self) -> Option<&Dxgi::IDXGIFactory5> { + match self { + Self::Factory4(_) => None, + Self::Factory5(f) => Some(f), + Self::Factory6(f) => Some(f), + } + } } -/// Tries to create a IDXGIFactory6, then a IDXGIFactory4, then a IDXGIFactory2, then a IDXGIFactory1, -/// returning the one that succeeds, or if the required_factory_type fails to be -/// created. pub fn create_factory( - required_factory_type: DxgiFactoryType, instance_flags: wgt::InstanceFlags, -) -> Result<(d3d12::DxgiLib, d3d12::DxgiFactory), crate::InstanceError> { - let lib_dxgi = d3d12::DxgiLib::new().map_err(|e| { +) -> Result<(DxgiLib, DxgiFactory), crate::InstanceError> { + let lib_dxgi = DxgiLib::new().map_err(|e| { crate::InstanceError::with_source(String::from("failed to load dxgi.dll"), e) })?; - let mut factory_flags = d3d12::FactoryCreationFlags::empty(); + let mut factory_flags = Dxgi::DXGI_CREATE_FACTORY_FLAGS::default(); if instance_flags.contains(wgt::InstanceFlags::VALIDATION) { // The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to // `CreateDXGIFactory2` if the debug interface is actually available. So // we check for whether it exists first. - match lib_dxgi.get_debug_interface1() { - Ok(pair) => match pair.into_result() { - Ok(_debug_controller) => { - factory_flags |= d3d12::FactoryCreationFlags::DEBUG; - } - Err(err) => { - log::warn!("Unable to enable DXGI debug interface: {}", err); - } - }, - Err(err) => { - log::warn!("Debug interface function for DXGI not found: {:?}", err); - } + if let Ok(Some(_)) = lib_dxgi.debug_interface1() { + factory_flags |= Dxgi::DXGI_CREATE_FACTORY_DEBUG; } // Intercept `OutputDebugString` calls super::exception::register_exception_handler(); } - // Try to create IDXGIFactory4 - let factory4 = match lib_dxgi.create_factory2(factory_flags) { - Ok(pair) => match pair.into_result() { - Ok(factory) => Some(factory), - // We hard error here as we _should have_ been able to make a factory4 but couldn't. - Err(err) => { - // err is a Cow, not an Error implementor - return Err(crate::InstanceError::new(format!( - "failed to create IDXGIFactory4: {err:?}" - ))); - } - }, - // If we require factory4, hard error. - Err(err) if required_factory_type == DxgiFactoryType::Factory4 => { + let factory4 = match lib_dxgi.create_factory4(factory_flags) { + Ok(factory) => factory, + Err(err) => { return Err(crate::InstanceError::with_source( - String::from("IDXGIFactory1 creation function not found"), + String::from("IDXGIFactory4 creation failed"), err, )); } - // If we don't print it to warn as all win7 will hit this case. - Err(err) => { - log::warn!("IDXGIFactory1 creation function not found: {err:?}"); - None - } }; - if let Some(factory4) = factory4 { - // Try to cast the IDXGIFactory4 into IDXGIFactory6 - let factory6 = unsafe { factory4.cast::().into_result() }; - match factory6 { - Ok(factory6) => { - return Ok((lib_dxgi, d3d12::DxgiFactory::Factory6(factory6))); - } - // If we require factory6, hard error. - Err(err) if required_factory_type == DxgiFactoryType::Factory6 => { - // err is a Cow, not an Error implementor - return Err(crate::InstanceError::new(format!( - "failed to cast IDXGIFactory4 to IDXGIFactory6: {err:?}" - ))); - } - // If we don't print it to warn. - Err(err) => { - log::warn!("Failed to cast IDXGIFactory4 to IDXGIFactory6: {:?}", err); - return Ok((lib_dxgi, d3d12::DxgiFactory::Factory4(factory4))); - } - } + if let Ok(factory6) = factory4.cast::() { + return Ok((lib_dxgi, DxgiFactory::Factory6(factory6))); } - // Try to create IDXGIFactory1 - let factory1 = match lib_dxgi.create_factory1() { - Ok(pair) => match pair.into_result() { - Ok(factory) => factory, - Err(err) => { - // err is a Cow, not an Error implementor - return Err(crate::InstanceError::new(format!( - "failed to create IDXGIFactory1: {err:?}" - ))); - } - }, - // We always require at least factory1, so hard error - Err(err) => { - return Err(crate::InstanceError::with_source( - String::from("IDXGIFactory1 creation function not found"), - err, - )); - } - }; - - // Try to cast the IDXGIFactory1 into IDXGIFactory2 - let factory2 = unsafe { factory1.cast::().into_result() }; - match factory2 { - Ok(factory2) => { - return Ok((lib_dxgi, d3d12::DxgiFactory::Factory2(factory2))); - } - // If we require factory2, hard error. - Err(err) if required_factory_type == DxgiFactoryType::Factory2 => { - // err is a Cow, not an Error implementor - return Err(crate::InstanceError::new(format!( - "failed to cast IDXGIFactory1 to IDXGIFactory2: {err:?}" - ))); - } - // If we don't print it to warn. - Err(err) => { - log::warn!("Failed to cast IDXGIFactory1 to IDXGIFactory2: {:?}", err); - } + if let Ok(factory5) = factory4.cast::() { + return Ok((lib_dxgi, DxgiFactory::Factory5(factory5))); } - // We tried to create 4 and 2, but only succeeded with 1. - Ok((lib_dxgi, d3d12::DxgiFactory::Factory1(factory1))) + Ok((lib_dxgi, DxgiFactory::Factory4(factory4))) } diff --git a/wgpu-hal/src/auxil/dxgi/result.rs b/wgpu-hal/src/auxil/dxgi/result.rs index 2ac4464568..61e3c6acf0 100644 --- a/wgpu-hal/src/auxil/dxgi/result.rs +++ b/wgpu-hal/src/auxil/dxgi/result.rs @@ -1,60 +1,32 @@ -use std::borrow::Cow; - -use winapi::shared::winerror; +use windows::Win32::{Foundation, Graphics::Dxgi}; pub(crate) trait HResult { - fn into_result(self) -> Result>; fn into_device_result(self, description: &str) -> Result; } -impl HResult<()> for i32 { - fn into_result(self) -> Result<(), Cow<'static, str>> { - if self >= 0 { - return Ok(()); - } - let description = match self { - winerror::E_UNEXPECTED => "unexpected", - winerror::E_NOTIMPL => "not implemented", - winerror::E_OUTOFMEMORY => "out of memory", - winerror::E_INVALIDARG => "invalid argument", - _ => return Err(Cow::Owned(format!("0x{:X}", self as u32))), - }; - Err(Cow::Borrowed(description)) - } - fn into_device_result(self, description: &str) -> Result<(), crate::DeviceError> { +impl HResult for windows::core::Result { + fn into_device_result(self, description: &str) -> Result { #![allow(unreachable_code)] - self.into_result().map_err(|err| { + self.map_err(|err| { log::error!("{} failed: {}", description, err); - match self { - winerror::E_OUTOFMEMORY => { + match err.code() { + Foundation::E_OUTOFMEMORY => { #[cfg(feature = "oom_panic")] panic!("{description} failed: Out of memory"); + crate::DeviceError::OutOfMemory } - winerror::DXGI_ERROR_DEVICE_RESET | winerror::DXGI_ERROR_DEVICE_REMOVED => { + Dxgi::DXGI_ERROR_DEVICE_RESET | Dxgi::DXGI_ERROR_DEVICE_REMOVED => { #[cfg(feature = "device_lost_panic")] panic!("{description} failed: Device lost ({err})"); + crate::DeviceError::Lost } _ => { #[cfg(feature = "internal_error_panic")] panic!("{description} failed: {err}"); + crate::DeviceError::Unexpected } } - - if self == winerror::E_OUTOFMEMORY { - crate::DeviceError::OutOfMemory - } else { - crate::DeviceError::Lost - } }) } } - -impl HResult for (T, i32) { - fn into_result(self) -> Result> { - self.1.into_result().map(|()| self.0) - } - fn into_device_result(self, description: &str) -> Result { - self.1.into_device_result(description).map(|()| self.0) - } -} diff --git a/wgpu-hal/src/auxil/dxgi/time.rs b/wgpu-hal/src/auxil/dxgi/time.rs index fd99c097d7..1b312fd651 100644 --- a/wgpu-hal/src/auxil/dxgi/time.rs +++ b/wgpu-hal/src/auxil/dxgi/time.rs @@ -1,22 +1,20 @@ #![allow(dead_code)] // IPresentationManager is unused currently -use std::mem; - -use winapi::um::{ - profileapi::{QueryPerformanceCounter, QueryPerformanceFrequency}, - winnt::LARGE_INTEGER, -}; +use windows::Win32::System::Performance::{QueryPerformanceCounter, QueryPerformanceFrequency}; pub enum PresentationTimer { - /// DXGI uses QueryPerformanceCounter + /// DXGI uses [`QueryPerformanceCounter()`] Dxgi { /// How many ticks of QPC per second frequency: u64, }, - /// IPresentationManager uses QueryInterruptTimePrecise + /// [`IPresentationManager`] uses [`QueryInterruptTimePrecise()`] + /// + /// [`IPresentationManager`]: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Graphics/CompositionSwapchain/struct.IPresentationManager.html + /// [`QueryInterruptTimePrecise()`]: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/WindowsProgramming/fn.QueryInterruptTimePrecise.html #[allow(non_snake_case)] IPresentationManager { - fnQueryInterruptTimePrecise: unsafe extern "system" fn(*mut winapi::ctypes::c_ulonglong), + fnQueryInterruptTimePrecise: unsafe extern "system" fn(*mut u64), }, } @@ -43,12 +41,13 @@ impl std::fmt::Debug for PresentationTimer { impl PresentationTimer { /// Create a presentation timer using QueryPerformanceFrequency (what DXGI uses for presentation times) pub fn new_dxgi() -> Self { - let mut frequency: LARGE_INTEGER = unsafe { mem::zeroed() }; - let success = unsafe { QueryPerformanceFrequency(&mut frequency) }; - assert_ne!(success, 0); + let mut frequency = 0; + unsafe { QueryPerformanceFrequency(&mut frequency) }.unwrap(); Self::Dxgi { - frequency: unsafe { *frequency.QuadPart() } as u64, + frequency: frequency + .try_into() + .expect("Frequency should not be negative"), } } @@ -59,10 +58,11 @@ impl PresentationTimer { // We need to load this explicitly, as QueryInterruptTimePrecise is only available on Windows 10+ // // Docs say it's in kernel32.dll, but it's actually in kernelbase.dll. + // api-ms-win-core-realtime-l1-1-1.dll let kernelbase = libloading::os::windows::Library::open_already_loaded("kernelbase.dll").unwrap(); // No concerns about lifetimes here as kernelbase is always there. - let ptr = unsafe { kernelbase.get(b"QueryInterruptTimePrecise").unwrap() }; + let ptr = unsafe { kernelbase.get(b"QueryInterruptTimePrecise\0").unwrap() }; Self::IPresentationManager { fnQueryInterruptTimePrecise: *ptr, } @@ -73,12 +73,11 @@ impl PresentationTimer { // Always do u128 math _after_ hitting the timing function. match *self { PresentationTimer::Dxgi { frequency } => { - let mut counter: LARGE_INTEGER = unsafe { mem::zeroed() }; - let success = unsafe { QueryPerformanceCounter(&mut counter) }; - assert_ne!(success, 0); + let mut counter = 0; + unsafe { QueryPerformanceCounter(&mut counter) }.unwrap(); // counter * (1_000_000_000 / freq) but re-ordered to make more precise - (unsafe { *counter.QuadPart() } as u128 * 1_000_000_000) / frequency as u128 + (counter as u128 * 1_000_000_000) / frequency as u128 } PresentationTimer::IPresentationManager { fnQueryInterruptTimePrecise, diff --git a/wgpu-hal/src/auxil/renderdoc.rs b/wgpu-hal/src/auxil/renderdoc.rs index 240d9dda29..3b08955fad 100644 --- a/wgpu-hal/src/auxil/renderdoc.rs +++ b/wgpu-hal/src/auxil/renderdoc.rs @@ -106,7 +106,7 @@ impl Default for RenderDoc { unsafe { Self::new() } } } -/// A implementation specific handle +/// An implementation specific handle pub type Handle = *mut os::raw::c_void; impl RenderDoc { diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 72b9d04b71..45d69f5584 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -1,15 +1,26 @@ -use crate::{ - auxil::{self, dxgi::result::HResult as _}, - dx12::{shader_compilation, SurfaceTarget}, +use std::{ + mem::{size_of, size_of_val}, + ptr, + sync::Arc, + thread, }; + use parking_lot::Mutex; -use std::{mem, ptr, sync::Arc, thread}; -use winapi::{ - shared::{ - dxgi, dxgi1_2, dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, minwindef::DWORD, windef, winerror, +use windows::{ + core::Interface as _, + Win32::{ + Graphics::{Direct3D, Direct3D12, Dxgi}, + UI::WindowsAndMessaging, + }, +}; + +use super::D3D12Lib; +use crate::{ + auxil::{ + self, + dxgi::{factory::DxgiAdapter, result::HResult}, }, - um::{d3d12 as d3d12_ty, d3d12sdklayers, winnt, winuser}, - Interface, + dx12::{shader_compilation, SurfaceTarget}, }; impl Drop for super::Adapter { @@ -30,91 +41,74 @@ impl Drop for super::Adapter { impl super::Adapter { pub unsafe fn report_live_objects(&self) { - if let Ok(debug_device) = unsafe { - self.raw - .cast::() - .into_result() - } { + if let Ok(debug_device) = self.raw.cast::() { unsafe { debug_device.ReportLiveDeviceObjects( - d3d12sdklayers::D3D12_RLDO_SUMMARY | d3d12sdklayers::D3D12_RLDO_IGNORE_INTERNAL, + Direct3D12::D3D12_RLDO_SUMMARY | Direct3D12::D3D12_RLDO_IGNORE_INTERNAL, ) - }; + } + .unwrap() } } - pub fn raw_adapter(&self) -> &d3d12::DxgiAdapter { + pub fn raw_adapter(&self) -> &DxgiAdapter { &self.raw } - #[allow(trivial_casts)] pub(super) fn expose( - adapter: d3d12::DxgiAdapter, - library: &Arc, + adapter: DxgiAdapter, + library: &Arc, instance_flags: wgt::InstanceFlags, dxc_container: Option>, ) -> Option> { // Create the device so that we can get the capabilities. let device = { profiling::scope!("ID3D12Device::create_device"); - match library.create_device(&adapter, d3d12::FeatureLevel::L11_0) { - Ok(pair) => match pair.into_result() { - Ok(device) => device, - Err(err) => { - log::warn!("Device creation failed: {}", err); - return None; - } - }, - Err(err) => { - log::warn!("Device creation function is not found: {:?}", err); - return None; - } - } + library + .create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0) + .ok()?? }; profiling::scope!("feature queries"); // Detect the highest supported feature level. let d3d_feature_level = [ - d3d12::FeatureLevel::L12_1, - d3d12::FeatureLevel::L12_0, - d3d12::FeatureLevel::L11_1, - d3d12::FeatureLevel::L11_0, + Direct3D::D3D_FEATURE_LEVEL_12_1, + Direct3D::D3D_FEATURE_LEVEL_12_0, + Direct3D::D3D_FEATURE_LEVEL_11_1, + Direct3D::D3D_FEATURE_LEVEL_11_0, ]; - let mut device_levels: d3d12_ty::D3D12_FEATURE_DATA_FEATURE_LEVELS = - unsafe { mem::zeroed() }; - device_levels.NumFeatureLevels = d3d_feature_level.len() as u32; - device_levels.pFeatureLevelsRequested = d3d_feature_level.as_ptr().cast(); + let mut device_levels = Direct3D12::D3D12_FEATURE_DATA_FEATURE_LEVELS { + NumFeatureLevels: d3d_feature_level.len() as u32, + pFeatureLevelsRequested: d3d_feature_level.as_ptr().cast(), + MaxSupportedFeatureLevel: Default::default(), + }; unsafe { device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_FEATURE_LEVELS, - ptr::from_mut(&mut device_levels).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_FEATURE_LEVELS, + <*mut _>::cast(&mut device_levels), + size_of_val(&device_levels) as u32, ) - }; - // This cast should never fail because we only requested feature levels that are already in the enum. - let max_feature_level = - d3d12::FeatureLevel::try_from(device_levels.MaxSupportedFeatureLevel) - .expect("Unexpected feature level"); + } + .unwrap(); + let max_feature_level = device_levels.MaxSupportedFeatureLevel; // We have found a possible adapter. // Acquire the device information. - let mut desc: dxgi1_2::DXGI_ADAPTER_DESC2 = unsafe { mem::zeroed() }; - unsafe { - adapter.unwrap_adapter2().GetDesc2(&mut desc); - } + let desc = unsafe { adapter.GetDesc2() }.unwrap(); let device_name = auxil::dxgi::conv::map_adapter_name(desc.Description); - let mut features_architecture: d3d12_ty::D3D12_FEATURE_DATA_ARCHITECTURE = - unsafe { mem::zeroed() }; - assert_eq!(0, unsafe { + let mut features_architecture = Direct3D12::D3D12_FEATURE_DATA_ARCHITECTURE::default(); + + unsafe { device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_ARCHITECTURE, - ptr::from_mut(&mut features_architecture).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_ARCHITECTURE, + <*mut _>::cast(&mut features_architecture), + size_of_val(&features_architecture) as u32, ) - }); + } + .unwrap(); let mut workarounds = super::Workarounds::default(); @@ -123,27 +117,25 @@ impl super::Adapter { name: device_name, vendor: desc.VendorId, device: desc.DeviceId, - device_type: if (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) != 0 { + device_type: if Dxgi::DXGI_ADAPTER_FLAG(desc.Flags as i32) + .contains(Dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) + { workarounds.avoid_cpu_descriptor_overwrites = true; wgt::DeviceType::Cpu - } else if features_architecture.UMA != 0 { + } else if features_architecture.UMA.as_bool() { wgt::DeviceType::IntegratedGpu } else { wgt::DeviceType::DiscreteGpu }, driver: { - let mut i: winnt::LARGE_INTEGER = unsafe { mem::zeroed() }; - if 0 == unsafe { - adapter.CheckInterfaceSupport(&dxgi::IDXGIDevice::uuidof(), &mut i) - } { - let quad_part = unsafe { *i.QuadPart() }; + if let Ok(i) = unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) } { const MASK: i64 = 0xFFFF; format!( "{}.{}.{}.{}", - quad_part >> 48, - (quad_part >> 32) & MASK, - (quad_part >> 16) & MASK, - quad_part & MASK + i >> 48, + (i >> 32) & MASK, + (i >> 16) & MASK, + i & MASK ) } else { String::new() @@ -152,84 +144,101 @@ impl super::Adapter { driver_info: String::new(), }; - let mut options: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS = unsafe { mem::zeroed() }; - assert_eq!(0, unsafe { + let mut options = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS::default(); + unsafe { device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS, - ptr::from_mut(&mut options).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_D3D12_OPTIONS, + <*mut _>::cast(&mut options), + size_of_val(&options) as u32, ) - }); + } + .unwrap(); let _depth_bounds_test_supported = { - let mut features2: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS2 = - unsafe { mem::zeroed() }; - let hr = unsafe { + let mut features2 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS2::default(); + unsafe { device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS2, - ptr::from_mut(&mut features2).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_D3D12_OPTIONS2, + <*mut _>::cast(&mut features2), + size_of_val(&features2) as u32, ) - }; - hr == 0 && features2.DepthBoundsTestSupported != 0 + } + .is_ok() + && features2.DepthBoundsTestSupported.as_bool() }; let casting_fully_typed_format_supported = { - let mut features3: crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS3 = - unsafe { mem::zeroed() }; - let hr = unsafe { + let mut features3 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS3::default(); + unsafe { device.CheckFeatureSupport( - 21, // D3D12_FEATURE_D3D12_OPTIONS3 - ptr::from_mut(&mut features3).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_D3D12_OPTIONS3, + <*mut _>::cast(&mut features3), + size_of_val(&features3) as u32, ) - }; - hr == 0 && features3.CastingFullyTypedFormatSupported != 0 + } + .is_ok() + && features3.CastingFullyTypedFormatSupported.as_bool() + }; + + let heap_create_not_zeroed = { + // For D3D12_HEAP_FLAG_CREATE_NOT_ZEROED we just need to + // make sure that options7 can be queried. See also: + // https://devblogs.microsoft.com/directx/coming-to-directx-12-more-control-over-memory-allocation/ + let mut features7 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS7::default(); + unsafe { + device.CheckFeatureSupport( + Direct3D12::D3D12_FEATURE_D3D12_OPTIONS7, + <*mut _>::cast(&mut features7), + size_of_val(&features7) as u32, + ) + } + .is_ok() }; let shader_model = if dxc_container.is_none() { naga::back::hlsl::ShaderModel::V5_1 } else { let mut versions = [ - crate::dx12::types::D3D_SHADER_MODEL_6_7, - crate::dx12::types::D3D_SHADER_MODEL_6_6, - crate::dx12::types::D3D_SHADER_MODEL_6_5, - crate::dx12::types::D3D_SHADER_MODEL_6_4, - crate::dx12::types::D3D_SHADER_MODEL_6_3, - crate::dx12::types::D3D_SHADER_MODEL_6_2, - crate::dx12::types::D3D_SHADER_MODEL_6_1, - crate::dx12::types::D3D_SHADER_MODEL_6_0, - crate::dx12::types::D3D_SHADER_MODEL_5_1, + Direct3D12::D3D_SHADER_MODEL_6_7, + Direct3D12::D3D_SHADER_MODEL_6_6, + Direct3D12::D3D_SHADER_MODEL_6_5, + Direct3D12::D3D_SHADER_MODEL_6_4, + Direct3D12::D3D_SHADER_MODEL_6_3, + Direct3D12::D3D_SHADER_MODEL_6_2, + Direct3D12::D3D_SHADER_MODEL_6_1, + Direct3D12::D3D_SHADER_MODEL_6_0, + Direct3D12::D3D_SHADER_MODEL_5_1, ] .iter(); match loop { if let Some(&sm) = versions.next() { - let mut sm = crate::dx12::types::D3D12_FEATURE_DATA_SHADER_MODEL { + let mut sm = Direct3D12::D3D12_FEATURE_DATA_SHADER_MODEL { HighestShaderModel: sm, }; - if 0 == unsafe { + if unsafe { device.CheckFeatureSupport( - 7, // D3D12_FEATURE_SHADER_MODEL - ptr::from_mut(&mut sm).cast(), - mem::size_of::() - as _, + Direct3D12::D3D12_FEATURE_SHADER_MODEL, + <*mut _>::cast(&mut sm), + size_of_val(&sm) as u32, ) - } { + } + .is_ok() + { break sm.HighestShaderModel; } } else { - break crate::dx12::types::D3D_SHADER_MODEL_5_1; + break Direct3D12::D3D_SHADER_MODEL_5_1; } } { - crate::dx12::types::D3D_SHADER_MODEL_5_1 => naga::back::hlsl::ShaderModel::V5_1, - crate::dx12::types::D3D_SHADER_MODEL_6_0 => naga::back::hlsl::ShaderModel::V6_0, - crate::dx12::types::D3D_SHADER_MODEL_6_1 => naga::back::hlsl::ShaderModel::V6_1, - crate::dx12::types::D3D_SHADER_MODEL_6_2 => naga::back::hlsl::ShaderModel::V6_2, - crate::dx12::types::D3D_SHADER_MODEL_6_3 => naga::back::hlsl::ShaderModel::V6_3, - crate::dx12::types::D3D_SHADER_MODEL_6_4 => naga::back::hlsl::ShaderModel::V6_4, - crate::dx12::types::D3D_SHADER_MODEL_6_5 => naga::back::hlsl::ShaderModel::V6_5, - crate::dx12::types::D3D_SHADER_MODEL_6_6 => naga::back::hlsl::ShaderModel::V6_6, - crate::dx12::types::D3D_SHADER_MODEL_6_7 => naga::back::hlsl::ShaderModel::V6_7, + Direct3D12::D3D_SHADER_MODEL_5_1 => naga::back::hlsl::ShaderModel::V5_1, + Direct3D12::D3D_SHADER_MODEL_6_0 => naga::back::hlsl::ShaderModel::V6_0, + Direct3D12::D3D_SHADER_MODEL_6_1 => naga::back::hlsl::ShaderModel::V6_1, + Direct3D12::D3D_SHADER_MODEL_6_2 => naga::back::hlsl::ShaderModel::V6_2, + Direct3D12::D3D_SHADER_MODEL_6_3 => naga::back::hlsl::ShaderModel::V6_3, + Direct3D12::D3D_SHADER_MODEL_6_4 => naga::back::hlsl::ShaderModel::V6_4, + Direct3D12::D3D_SHADER_MODEL_6_5 => naga::back::hlsl::ShaderModel::V6_5, + Direct3D12::D3D_SHADER_MODEL_6_6 => naga::back::hlsl::ShaderModel::V6_6, + Direct3D12::D3D_SHADER_MODEL_6_7 => naga::back::hlsl::ShaderModel::V6_7, _ => unreachable!(), } }; @@ -237,15 +246,15 @@ impl super::Adapter { let private_caps = super::PrivateCapabilities { instance_flags, heterogeneous_resource_heaps: options.ResourceHeapTier - != d3d12_ty::D3D12_RESOURCE_HEAP_TIER_1, - memory_architecture: if features_architecture.UMA != 0 { + != Direct3D12::D3D12_RESOURCE_HEAP_TIER_1, + memory_architecture: if features_architecture.UMA.as_bool() { super::MemoryArchitecture::Unified { - cache_coherent: features_architecture.CacheCoherentUMA != 0, + cache_coherent: features_architecture.CacheCoherentUMA.as_bool(), } } else { super::MemoryArchitecture::NonUnified }, - heap_create_not_zeroed: false, //TODO: winapi support for Options7 + heap_create_not_zeroed, casting_fully_typed_format_supported, // See https://github.com/gfx-rs/wgpu/issues/3552 suballocation_supported: !info.name.contains("Iris(R) Xe"), @@ -256,29 +265,29 @@ impl super::Adapter { let tier3_practical_descriptor_limit = 1 << 20; let (full_heap_count, uav_count) = match options.ResourceBindingTier { - d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => { + Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => { let uav_count = match max_feature_level { - d3d12::FeatureLevel::L11_0 => 8, + Direct3D::D3D_FEATURE_LEVEL_11_0 => 8, _ => 64, }; ( - d3d12_ty::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1, + Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1, uav_count, ) } - d3d12_ty::D3D12_RESOURCE_BINDING_TIER_2 => ( - d3d12_ty::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2, + Direct3D12::D3D12_RESOURCE_BINDING_TIER_2 => ( + Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2, 64, ), - d3d12_ty::D3D12_RESOURCE_BINDING_TIER_3 => ( + Direct3D12::D3D12_RESOURCE_BINDING_TIER_3 => ( tier3_practical_descriptor_limit, tier3_practical_descriptor_limit, ), other => { - log::warn!("Unknown resource binding tier {}", other); + log::warn!("Unknown resource binding tier {:?}", other); ( - d3d12_ty::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1, + Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1, 8, ) } @@ -314,14 +323,14 @@ impl super::Adapter { // write the results there, and issue a bunch of copy commands. //| wgt::Features::PIPELINE_STATISTICS_QUERY - if max_feature_level as u32 >= d3d12::FeatureLevel::L11_1 as u32 { + if max_feature_level.0 >= Direct3D::D3D_FEATURE_LEVEL_11_1.0 { features |= wgt::Features::VERTEX_WRITABLE_STORAGE; } features.set( wgt::Features::CONSERVATIVE_RASTERIZATION, options.ConservativeRasterizationTier - != d3d12_ty::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED, + != Direct3D12::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED, ); features.set( @@ -332,60 +341,62 @@ impl super::Adapter { ); let bgra8unorm_storage_supported = { - let mut bgra8unorm_info: d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT = - unsafe { mem::zeroed() }; - bgra8unorm_info.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + let mut bgra8unorm_info = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT { + Format: Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM, + ..Default::default() + }; let hr = unsafe { device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT, - ptr::from_mut(&mut bgra8unorm_info).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT, + <*mut _>::cast(&mut bgra8unorm_info), + size_of_val(&bgra8unorm_info) as u32, ) }; - hr == 0 - && (bgra8unorm_info.Support2 & d3d12_ty::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE != 0) + hr.is_ok() + && bgra8unorm_info + .Support2 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE) }; features.set( wgt::Features::BGRA8UNORM_STORAGE, bgra8unorm_storage_supported, ); - let mut features1: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS1 = unsafe { mem::zeroed() }; + let mut features1 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS1::default(); let hr = unsafe { device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS1, - ptr::from_mut(&mut features1).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_D3D12_OPTIONS1, + <*mut _>::cast(&mut features1), + size_of_val(&features1) as u32, ) }; features.set( wgt::Features::SHADER_INT64, shader_model >= naga::back::hlsl::ShaderModel::V6_0 - && hr == 0 - && features1.Int64ShaderOps != 0, + && hr.is_ok() + && features1.Int64ShaderOps.as_bool(), ); features.set( wgt::Features::SUBGROUP, shader_model >= naga::back::hlsl::ShaderModel::V6_0 - && hr == 0 - && features1.WaveOps != 0, + && hr.is_ok() + && features1.WaveOps.as_bool(), ); let atomic_int64_on_typed_resource_supported = { - let mut features9: crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS9 = - unsafe { mem::zeroed() }; - let hr = unsafe { + let mut features9 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS9::default(); + unsafe { device.CheckFeatureSupport( - 37, // D3D12_FEATURE_D3D12_OPTIONS9 - ptr::from_mut(&mut features9).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_D3D12_OPTIONS9, + <*mut _>::cast(&mut features9), + size_of_val(&features9) as u32, ) - }; - hr == 0 - && features9.AtomicInt64OnGroupSharedSupported != 0 - && features9.AtomicInt64OnTypedResourceSupported != 0 + } + .is_ok() + && features9.AtomicInt64OnGroupSharedSupported.as_bool() + && features9.AtomicInt64OnTypedResourceSupported.as_bool() }; features.set( wgt::Features::SHADER_INT64_ATOMIC_ALL_OPS | wgt::Features::SHADER_INT64_ATOMIC_MIN_MAX, @@ -425,11 +436,11 @@ impl super::Adapter { features, capabilities: crate::Capabilities { limits: wgt::Limits { - max_texture_dimension_1d: d3d12_ty::D3D12_REQ_TEXTURE1D_U_DIMENSION, - max_texture_dimension_2d: d3d12_ty::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION - .min(d3d12_ty::D3D12_REQ_TEXTURECUBE_DIMENSION), - max_texture_dimension_3d: d3d12_ty::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION, - max_texture_array_layers: d3d12_ty::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION, + max_texture_dimension_1d: Direct3D12::D3D12_REQ_TEXTURE1D_U_DIMENSION, + max_texture_dimension_2d: Direct3D12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION + .min(Direct3D12::D3D12_REQ_TEXTURECUBE_DIMENSION), + max_texture_dimension_3d: Direct3D12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION, + max_texture_array_layers: Direct3D12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION, max_bind_groups: crate::MAX_BIND_GROUPS as u32, max_bindings_per_bind_group: 65535, // dynamic offsets take a root constant, so we expose the minimum here @@ -438,12 +449,12 @@ impl super::Adapter { max_dynamic_storage_buffers_per_pipeline_layout: base .max_dynamic_storage_buffers_per_pipeline_layout, max_sampled_textures_per_shader_stage: match options.ResourceBindingTier { - d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => 128, + Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => 128, _ => full_heap_count, }, max_samplers_per_shader_stage: match options.ResourceBindingTier { - d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => 16, - _ => d3d12_ty::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE, + Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => 16, + _ => Direct3D12::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE, }, // these both account towards `uav_count`, but we can't express the limit as as sum // of the two, so we divide it by 4 to account for the worst case scenario @@ -452,12 +463,12 @@ impl super::Adapter { max_storage_textures_per_shader_stage: uav_count / 4, max_uniform_buffers_per_shader_stage: full_heap_count, max_uniform_buffer_binding_size: - d3d12_ty::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16, + Direct3D12::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16, max_storage_buffer_binding_size: auxil::MAX_I32_BINDING_SIZE, - max_vertex_buffers: d3d12_ty::D3D12_VS_INPUT_REGISTER_COUNT + max_vertex_buffers: Direct3D12::D3D12_VS_INPUT_REGISTER_COUNT .min(crate::MAX_VERTEX_BUFFERS as u32), - max_vertex_attributes: d3d12_ty::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT, - max_vertex_buffer_array_stride: d3d12_ty::D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES, + max_vertex_attributes: Direct3D12::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT, + max_vertex_buffer_array_stride: Direct3D12::D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES, min_subgroup_size: 4, // Not using `features1.WaveLaneCountMin` as it is unreliable max_subgroup_size: 128, // The push constants are part of the root signature which @@ -480,19 +491,19 @@ impl super::Adapter { // Source: https://learn.microsoft.com/en-us/windows/win32/direct3d12/root-signature-limits#memory-limits-and-costs max_push_constant_size: 128, min_uniform_buffer_offset_alignment: - d3d12_ty::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, + Direct3D12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, min_storage_buffer_offset_alignment: 4, max_inter_stage_shader_components: base.max_inter_stage_shader_components, max_color_attachments, max_color_attachment_bytes_per_sample, max_compute_workgroup_storage_size: base.max_compute_workgroup_storage_size, //TODO? max_compute_invocations_per_workgroup: - d3d12_ty::D3D12_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP, - max_compute_workgroup_size_x: d3d12_ty::D3D12_CS_THREAD_GROUP_MAX_X, - max_compute_workgroup_size_y: d3d12_ty::D3D12_CS_THREAD_GROUP_MAX_Y, - max_compute_workgroup_size_z: d3d12_ty::D3D12_CS_THREAD_GROUP_MAX_Z, + Direct3D12::D3D12_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP, + max_compute_workgroup_size_x: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_X, + max_compute_workgroup_size_y: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_Y, + max_compute_workgroup_size_z: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_Z, max_compute_workgroups_per_dimension: - d3d12_ty::D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, + Direct3D12::D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, // Dx12 does not expose a maximum buffer size in the API. // This limit is chosen to avoid potential issues with drivers should they internally // store buffer sizes using 32 bit ints (a situation we have already encountered with vulkan). @@ -501,13 +512,16 @@ impl super::Adapter { }, alignments: crate::Alignments { buffer_copy_offset: wgt::BufferSize::new( - d3d12_ty::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as u64, + Direct3D12::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as u64, ) .unwrap(), buffer_copy_pitch: wgt::BufferSize::new( - d3d12_ty::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64, + Direct3D12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64, ) .unwrap(), + // Direct3D correctly bounds-checks all array accesses: + // https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#18.6.8.2%20Device%20Memory%20Reads + uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(), }, downlevel, }, @@ -524,16 +538,18 @@ impl crate::Adapter for super::Adapter { limits: &wgt::Limits, memory_hints: &wgt::MemoryHints, ) -> Result, crate::DeviceError> { - let queue = { + let queue: Direct3D12::ID3D12CommandQueue = { profiling::scope!("ID3D12Device::CreateCommandQueue"); - self.device - .create_command_queue( - d3d12::CmdListType::Direct, - d3d12::Priority::Normal, - d3d12::CommandQueueFlags::empty(), - 0, - ) - .into_device_result("Queue creation")? + unsafe { + self.device + .CreateCommandQueue(&Direct3D12::D3D12_COMMAND_QUEUE_DESC { + Type: Direct3D12::D3D12_COMMAND_LIST_TYPE_DIRECT, + Priority: Direct3D12::D3D12_COMMAND_QUEUE_PRIORITY_NORMAL.0, + Flags: Direct3D12::D3D12_COMMAND_QUEUE_FLAG_NONE, + NodeMask: 0, + }) + } + .into_device_result("Queue creation")? }; let device = super::Device::new( @@ -554,7 +570,6 @@ impl crate::Adapter for super::Adapter { }) } - #[allow(trivial_casts)] unsafe fn texture_format_capabilities( &self, format: wgt::TextureFormat, @@ -579,99 +594,118 @@ impl crate::Adapter for super::Adapter { } .unwrap(); - let mut data = d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT { + let mut data = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT { Format: raw_format, - Support1: unsafe { mem::zeroed() }, - Support2: unsafe { mem::zeroed() }, + ..Default::default() }; - assert_eq!(winerror::S_OK, unsafe { + unsafe { self.device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT, - ptr::from_mut(&mut data).cast(), - mem::size_of::() as _, + Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT, + <*mut _>::cast(&mut data), + size_of_val(&data) as u32, ) - }); + } + .unwrap(); // Because we use a different format for SRV and UAV views of depth textures, we need to check // the features that use SRV/UAVs using the no-depth format. - let mut data_srv_uav = d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT { + let mut data_srv_uav = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT { Format: srv_uav_format, - Support1: d3d12_ty::D3D12_FORMAT_SUPPORT1_NONE, - Support2: d3d12_ty::D3D12_FORMAT_SUPPORT2_NONE, + Support1: Direct3D12::D3D12_FORMAT_SUPPORT1_NONE, + Support2: Direct3D12::D3D12_FORMAT_SUPPORT2_NONE, }; if raw_format != srv_uav_format { // Only-recheck if we're using a different format - assert_eq!(winerror::S_OK, unsafe { + unsafe { self.device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT, + Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT, ptr::addr_of_mut!(data_srv_uav).cast(), - DWORD::try_from(mem::size_of::()) - .unwrap(), + size_of::() as u32, ) - }); + } + .unwrap(); } else { // Same format, just copy over. data_srv_uav = data; } let mut caps = Tfc::COPY_SRC | Tfc::COPY_DST; - let is_texture = data.Support1 - & (d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE1D - | d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE2D - | d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE3D - | d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURECUBE) + // Cannot use the contains() helper, and windows-rs doesn't provide a .intersect() helper + let is_texture = (data.Support1 + & (Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE1D + | Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE2D + | Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE3D + | Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURECUBE)) + .0 != 0; // SRVs use srv_uav_format caps.set( Tfc::SAMPLED, - is_texture && data_srv_uav.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_SHADER_LOAD != 0, + is_texture + && data_srv_uav + .Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_SHADER_LOAD), ); caps.set( Tfc::SAMPLED_LINEAR, - data_srv_uav.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE != 0, + data_srv_uav + .Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE), ); caps.set( Tfc::COLOR_ATTACHMENT, - data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_RENDER_TARGET != 0, + data.Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET), ); caps.set( Tfc::COLOR_ATTACHMENT_BLEND, - data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_BLENDABLE != 0, + data.Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_BLENDABLE), ); caps.set( Tfc::DEPTH_STENCIL_ATTACHMENT, - data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL != 0, + data.Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL), ); // UAVs use srv_uav_format caps.set( Tfc::STORAGE, - data_srv_uav.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW - != 0, + data_srv_uav + .Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW), ); caps.set( Tfc::STORAGE_READ_WRITE, - data_srv_uav.Support2 & d3d12_ty::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD != 0, + data_srv_uav + .Support2 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD), ); // We load via UAV/SRV so use srv_uav_format let no_msaa_load = caps.contains(Tfc::SAMPLED) - && data_srv_uav.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD == 0; - - let no_msaa_target = data.Support1 - & (d3d12_ty::D3D12_FORMAT_SUPPORT1_RENDER_TARGET - | d3d12_ty::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) + && !data_srv_uav + .Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD); + + let no_msaa_target = (data.Support1 + & (Direct3D12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET + | Direct3D12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) + .0 != 0 - && data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET == 0; + && !data + .Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET); caps.set( Tfc::MULTISAMPLE_RESOLVE, - data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE != 0, + data.Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE), ); - let mut ms_levels = d3d12_ty::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS { + let mut ms_levels = Direct3D12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS { Format: raw_format, SampleCount: 0, - Flags: d3d12_ty::D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE, + Flags: Direct3D12::D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE, NumQualityLevels: 0, }; @@ -680,11 +714,12 @@ impl crate::Adapter for super::Adapter { if unsafe { self.device.CheckFeatureSupport( - d3d12_ty::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, + Direct3D12::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, <*mut _>::cast(&mut ms_levels), - mem::size_of::() as _, + size_of_val(&ms_levels) as u32, ) - } == winerror::S_OK + } + .is_ok() && ms_levels.NumQualityLevels != 0 { caps.set(tfc, !no_msaa_load && !no_msaa_target); @@ -706,8 +741,9 @@ impl crate::Adapter for super::Adapter { let current_extent = { match surface.target { SurfaceTarget::WndHandle(wnd_handle) => { - let mut rect: windef::RECT = unsafe { mem::zeroed() }; - if unsafe { winuser::GetClientRect(wnd_handle, &mut rect) } != 0 { + let mut rect = Default::default(); + if unsafe { WindowsAndMessaging::GetClientRect(wnd_handle, &mut rect) }.is_ok() + { Some(wgt::Extent3d { width: (rect.right - rect.left) as u32, height: (rect.bottom - rect.top) as u32, diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 0356b91978..00f56cdb5f 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -1,11 +1,15 @@ -use crate::auxil::{self, dxgi::result::HResult as _}; +use std::{mem, ops::Range}; + +use windows::Win32::{Foundation, Graphics::Direct3D12}; use super::conv; -use std::{mem, ops::Range, ptr}; -use winapi::um::d3d12 as d3d12_ty; +use crate::{ + auxil::{self, dxgi::result::HResult as _}, + dx12::borrow_interface_temporarily, +}; -fn make_box(origin: &wgt::Origin3d, size: &crate::CopyExtent) -> d3d12_ty::D3D12_BOX { - d3d12_ty::D3D12_BOX { +fn make_box(origin: &wgt::Origin3d, size: &crate::CopyExtent) -> Direct3D12::D3D12_BOX { + Direct3D12::D3D12_BOX { left: origin.x, top: origin.y, right: origin.x + size.width, @@ -19,11 +23,11 @@ impl crate::BufferTextureCopy { fn to_subresource_footprint( &self, format: wgt::TextureFormat, - ) -> d3d12_ty::D3D12_PLACED_SUBRESOURCE_FOOTPRINT { + ) -> Direct3D12::D3D12_PLACED_SUBRESOURCE_FOOTPRINT { let (block_width, _) = format.block_dimensions(); - d3d12_ty::D3D12_PLACED_SUBRESOURCE_FOOTPRINT { + Direct3D12::D3D12_PLACED_SUBRESOURCE_FOOTPRINT { Offset: self.buffer_layout.offset, - Footprint: d3d12_ty::D3D12_SUBRESOURCE_FOOTPRINT { + Footprint: Direct3D12::D3D12_SUBRESOURCE_FOOTPRINT { Format: auxil::dxgi::conv::map_texture_format_for_copy( format, self.texture_base.aspect, @@ -40,7 +44,7 @@ impl crate::BufferTextureCopy { .unwrap(); (self.size.width / block_width) * block_size }); - wgt::math::align_to(actual, d3d12_ty::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) + wgt::math::align_to(actual, Direct3D12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) }, }, } @@ -69,20 +73,22 @@ impl super::CommandEncoder { self.pass.kind = kind; if let Some(label) = label { let (wide_label, size) = self.temp.prepare_marker(label); - unsafe { list.BeginEvent(0, wide_label.as_ptr().cast(), size) }; + unsafe { list.BeginEvent(0, Some(wide_label.as_ptr().cast()), size) }; self.pass.has_label = true; } self.pass.dirty_root_elements = 0; self.pass.dirty_vertex_buffers = 0; - list.set_descriptor_heaps(&[ - self.shared.heap_views.raw.clone(), - self.shared.heap_samplers.raw.clone(), - ]); + unsafe { + list.SetDescriptorHeaps(&[ + Some(self.shared.heap_views.raw.clone()), + Some(self.shared.heap_samplers.raw.clone()), + ]) + }; } unsafe fn end_pass(&mut self) { let list = self.list.as_ref().unwrap(); - list.set_descriptor_heaps(&[]); + unsafe { list.SetDescriptorHeaps(&[]) }; if self.pass.has_label { unsafe { list.EndEvent() }; } @@ -97,8 +103,7 @@ impl super::CommandEncoder { unsafe { list.IASetVertexBuffers( index, - 1, - self.pass.vertex_buffers.as_ptr().offset(index as isize), + Some(&self.pass.vertex_buffers[index as usize..][..1]), ); } } @@ -147,7 +152,7 @@ impl super::CommandEncoder { self.update_root_elements(); } - //Note: we have to call this lazily before draw calls. Otherwise, D3D complains + // Note: we have to call this lazily before draw calls. Otherwise, D3D complains // about the root parameters being incompatible with root signature. fn update_root_elements(&mut self) { use super::{BufferViewKind as Bvk, PassKind as Pk}; @@ -165,8 +170,12 @@ impl super::CommandEncoder { for offset in info.range.clone() { let val = self.pass.constant_data[offset as usize]; match self.pass.kind { - Pk::Render => list.set_graphics_root_constant(index, val, offset), - Pk::Compute => list.set_compute_root_constant(index, val, offset), + Pk::Render => unsafe { + list.SetGraphicsRoot32BitConstant(index, val, offset) + }, + Pk::Compute => unsafe { + list.SetComputeRoot32BitConstant(index, val, offset) + }, Pk::Transfer => (), } } @@ -177,41 +186,42 @@ impl super::CommandEncoder { other, } => match self.pass.kind { Pk::Render => { - list.set_graphics_root_constant(index, first_vertex as u32, 0); - list.set_graphics_root_constant(index, first_instance, 1); + unsafe { list.SetGraphicsRoot32BitConstant(index, first_vertex as u32, 0) }; + unsafe { list.SetGraphicsRoot32BitConstant(index, first_instance, 1) }; } Pk::Compute => { - list.set_compute_root_constant(index, first_vertex as u32, 0); - list.set_compute_root_constant(index, first_instance, 1); - list.set_compute_root_constant(index, other, 2); + unsafe { list.SetComputeRoot32BitConstant(index, first_vertex as u32, 0) }; + unsafe { list.SetComputeRoot32BitConstant(index, first_instance, 1) }; + unsafe { list.SetComputeRoot32BitConstant(index, other, 2) }; } Pk::Transfer => (), }, super::RootElement::Table(descriptor) => match self.pass.kind { - Pk::Render => list.set_graphics_root_descriptor_table(index, descriptor), - Pk::Compute => list.set_compute_root_descriptor_table(index, descriptor), + Pk::Render => unsafe { list.SetGraphicsRootDescriptorTable(index, descriptor) }, + Pk::Compute => unsafe { list.SetComputeRootDescriptorTable(index, descriptor) }, Pk::Transfer => (), }, super::RootElement::DynamicOffsetBuffer { kind, address } => { + let address = address.ptr; match (self.pass.kind, kind) { - (Pk::Render, Bvk::Constant) => { - list.set_graphics_root_constant_buffer_view(index, address) - } - (Pk::Compute, Bvk::Constant) => { - list.set_compute_root_constant_buffer_view(index, address) - } - (Pk::Render, Bvk::ShaderResource) => { - list.set_graphics_root_shader_resource_view(index, address) - } - (Pk::Compute, Bvk::ShaderResource) => { - list.set_compute_root_shader_resource_view(index, address) - } - (Pk::Render, Bvk::UnorderedAccess) => { - list.set_graphics_root_unordered_access_view(index, address) - } - (Pk::Compute, Bvk::UnorderedAccess) => { - list.set_compute_root_unordered_access_view(index, address) - } + (Pk::Render, Bvk::Constant) => unsafe { + list.SetGraphicsRootConstantBufferView(index, address) + }, + (Pk::Compute, Bvk::Constant) => unsafe { + list.SetComputeRootConstantBufferView(index, address) + }, + (Pk::Render, Bvk::ShaderResource) => unsafe { + list.SetGraphicsRootShaderResourceView(index, address) + }, + (Pk::Compute, Bvk::ShaderResource) => unsafe { + list.SetComputeRootShaderResourceView(index, address) + }, + (Pk::Render, Bvk::UnorderedAccess) => unsafe { + list.SetGraphicsRootUnorderedAccessView(index, address) + }, + (Pk::Compute, Bvk::UnorderedAccess) => unsafe { + list.SetComputeRootUnorderedAccessView(index, address) + }, (Pk::Transfer, _) => (), } } @@ -239,7 +249,7 @@ impl super::CommandEncoder { self.write_timestamp( &crate::dx12::QuerySet { raw: query_set_raw, - raw_ty: d3d12_ty::D3D12_QUERY_TYPE_TIMESTAMP, + raw_ty: Direct3D12::D3D12_QUERY_TYPE_TIMESTAMP, }, index, ); @@ -254,9 +264,8 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> { let list = loop { if let Some(list) = self.free_lists.pop() { - let reset_result = list - .reset(&self.allocator, d3d12::PipelineState::null()) - .into_result(); + // TODO: Is an error expected here and should we print it? + let reset_result = unsafe { list.Reset(&self.allocator, None) }; if reset_result.is_ok() { break Some(list); } @@ -268,19 +277,20 @@ impl crate::CommandEncoder for super::CommandEncoder { let list = if let Some(list) = list { list } else { - self.device - .create_graphics_command_list( - d3d12::CmdListType::Direct, - &self.allocator, - d3d12::PipelineState::null(), + unsafe { + self.device.CreateCommandList( 0, + Direct3D12::D3D12_COMMAND_LIST_TYPE_DIRECT, + &self.allocator, + None, ) - .into_device_result("Create command list")? + } + .into_device_result("Create command list")? }; if let Some(label) = label { - let cwstr = conv::map_label(label); - unsafe { list.SetName(cwstr.as_ptr()) }; + unsafe { list.SetName(&windows::core::HSTRING::from(label)) } + .into_device_result("SetName")?; } self.list = Some(list); @@ -290,22 +300,23 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn discard_encoding(&mut self) { if let Some(list) = self.list.take() { - if list.close().into_result().is_ok() { + if unsafe { list.Close() }.is_ok() { self.free_lists.push(list); } } } unsafe fn end_encoding(&mut self) -> Result { let raw = self.list.take().unwrap(); - raw.close() - .into_device_result("GraphicsCommandList::close")?; + unsafe { raw.Close() }.into_device_result("GraphicsCommandList::close")?; Ok(super::CommandBuffer { raw }) } unsafe fn reset_all>(&mut self, command_buffers: I) { for cmd_buf in command_buffers { self.free_lists.push(cmd_buf.raw); } - self.allocator.reset(); + if let Err(e) = unsafe { self.allocator.Reset() } { + log::error!("ID3D12CommandAllocator::Reset() failed with {e}"); + } } unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) @@ -318,30 +329,34 @@ impl crate::CommandEncoder for super::CommandEncoder { let s0 = conv::map_buffer_usage_to_state(barrier.usage.start); let s1 = conv::map_buffer_usage_to_state(barrier.usage.end); if s0 != s1 { - let mut raw = d3d12_ty::D3D12_RESOURCE_BARRIER { - Type: d3d12_ty::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, - Flags: d3d12_ty::D3D12_RESOURCE_BARRIER_FLAG_NONE, - u: unsafe { mem::zeroed() }, - }; - unsafe { - *raw.u.Transition_mut() = d3d12_ty::D3D12_RESOURCE_TRANSITION_BARRIER { - pResource: barrier.buffer.resource.as_mut_ptr(), - Subresource: d3d12_ty::D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, - StateBefore: s0, - StateAfter: s1, - } + let raw = Direct3D12::D3D12_RESOURCE_BARRIER { + Type: Direct3D12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + Flags: Direct3D12::D3D12_RESOURCE_BARRIER_FLAG_NONE, + Anonymous: Direct3D12::D3D12_RESOURCE_BARRIER_0 { + Transition: mem::ManuallyDrop::new( + Direct3D12::D3D12_RESOURCE_TRANSITION_BARRIER { + pResource: unsafe { + borrow_interface_temporarily(&barrier.buffer.resource) + }, + Subresource: Direct3D12::D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, + StateBefore: s0, + StateAfter: s1, + }, + ), + }, }; self.temp.barriers.push(raw); } else if barrier.usage.start == crate::BufferUses::STORAGE_READ_WRITE { - let mut raw = d3d12_ty::D3D12_RESOURCE_BARRIER { - Type: d3d12_ty::D3D12_RESOURCE_BARRIER_TYPE_UAV, - Flags: d3d12_ty::D3D12_RESOURCE_BARRIER_FLAG_NONE, - u: unsafe { mem::zeroed() }, - }; - unsafe { - *raw.u.UAV_mut() = d3d12_ty::D3D12_RESOURCE_UAV_BARRIER { - pResource: barrier.buffer.resource.as_mut_ptr(), - } + let raw = Direct3D12::D3D12_RESOURCE_BARRIER { + Type: Direct3D12::D3D12_RESOURCE_BARRIER_TYPE_UAV, + Flags: Direct3D12::D3D12_RESOURCE_BARRIER_FLAG_NONE, + Anonymous: Direct3D12::D3D12_RESOURCE_BARRIER_0 { + UAV: mem::ManuallyDrop::new(Direct3D12::D3D12_RESOURCE_UAV_BARRIER { + pResource: unsafe { + borrow_interface_temporarily(&barrier.buffer.resource) + }, + }), + }, }; self.temp.barriers.push(raw); } @@ -352,7 +367,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.list .as_ref() .unwrap() - .ResourceBarrier(self.temp.barriers.len() as u32, self.temp.barriers.as_ptr()) + .ResourceBarrier(&self.temp.barriers) }; } } @@ -367,18 +382,21 @@ impl crate::CommandEncoder for super::CommandEncoder { let s0 = conv::map_texture_usage_to_state(barrier.usage.start); let s1 = conv::map_texture_usage_to_state(barrier.usage.end); if s0 != s1 { - let mut raw = d3d12_ty::D3D12_RESOURCE_BARRIER { - Type: d3d12_ty::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, - Flags: d3d12_ty::D3D12_RESOURCE_BARRIER_FLAG_NONE, - u: unsafe { mem::zeroed() }, - }; - unsafe { - *raw.u.Transition_mut() = d3d12_ty::D3D12_RESOURCE_TRANSITION_BARRIER { - pResource: barrier.texture.resource.as_mut_ptr(), - Subresource: d3d12_ty::D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, - StateBefore: s0, - StateAfter: s1, - } + let mut raw = Direct3D12::D3D12_RESOURCE_BARRIER { + Type: Direct3D12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + Flags: Direct3D12::D3D12_RESOURCE_BARRIER_FLAG_NONE, + Anonymous: Direct3D12::D3D12_RESOURCE_BARRIER_0 { + Transition: mem::ManuallyDrop::new( + Direct3D12::D3D12_RESOURCE_TRANSITION_BARRIER { + pResource: unsafe { + borrow_interface_temporarily(&barrier.texture.resource) + }, + Subresource: Direct3D12::D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, + StateBefore: s0, + StateAfter: s1, + }, + ), + }, }; let tex_mip_level_count = barrier.texture.mip_level_count; @@ -419,26 +437,25 @@ impl crate::CommandEncoder for super::CommandEncoder { for mip_level in barrier.range.mip_range(tex_mip_level_count) { for array_layer in barrier.range.layer_range(tex_array_layer_count) { for plane in planes.clone() { - unsafe { - raw.u.Transition_mut().Subresource = barrier - .texture - .calc_subresource(mip_level, array_layer, plane); - }; - self.temp.barriers.push(raw); + unsafe { &mut *raw.Anonymous.Transition }.Subresource = barrier + .texture + .calc_subresource(mip_level, array_layer, plane); + self.temp.barriers.push(raw.clone()); } } } } } else if barrier.usage.start == crate::TextureUses::STORAGE_READ_WRITE { - let mut raw = d3d12_ty::D3D12_RESOURCE_BARRIER { - Type: d3d12_ty::D3D12_RESOURCE_BARRIER_TYPE_UAV, - Flags: d3d12_ty::D3D12_RESOURCE_BARRIER_FLAG_NONE, - u: unsafe { mem::zeroed() }, - }; - unsafe { - *raw.u.UAV_mut() = d3d12_ty::D3D12_RESOURCE_UAV_BARRIER { - pResource: barrier.texture.resource.as_mut_ptr(), - } + let raw = Direct3D12::D3D12_RESOURCE_BARRIER { + Type: Direct3D12::D3D12_RESOURCE_BARRIER_TYPE_UAV, + Flags: Direct3D12::D3D12_RESOURCE_BARRIER_FLAG_NONE, + Anonymous: Direct3D12::D3D12_RESOURCE_BARRIER_0 { + UAV: mem::ManuallyDrop::new(Direct3D12::D3D12_RESOURCE_UAV_BARRIER { + pResource: unsafe { + borrow_interface_temporarily(&barrier.texture.resource) + }, + }), + }, }; self.temp.barriers.push(raw); } @@ -449,7 +466,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.list .as_ref() .unwrap() - .ResourceBarrier(self.temp.barriers.len() as u32, self.temp.barriers.as_ptr()) + .ResourceBarrier(&self.temp.barriers) }; } } @@ -460,13 +477,7 @@ impl crate::CommandEncoder for super::CommandEncoder { while offset < range.end { let size = super::ZERO_BUFFER_SIZE.min(range.end - offset); unsafe { - list.CopyBufferRegion( - buffer.resource.as_mut_ptr(), - offset, - self.shared.zero_buffer.as_mut_ptr(), - 0, - size, - ) + list.CopyBufferRegion(&buffer.resource, offset, &self.shared.zero_buffer, 0, size) }; offset += size; } @@ -484,9 +495,9 @@ impl crate::CommandEncoder for super::CommandEncoder { for r in regions { unsafe { list.CopyBufferRegion( - dst.resource.as_mut_ptr(), + &dst.resource, r.dst_offset, - src.resource.as_mut_ptr(), + &src.resource, r.src_offset, r.size.get(), ) @@ -504,26 +515,25 @@ impl crate::CommandEncoder for super::CommandEncoder { T: Iterator, { let list = self.list.as_ref().unwrap(); - let mut src_location = d3d12_ty::D3D12_TEXTURE_COPY_LOCATION { - pResource: src.resource.as_mut_ptr(), - Type: d3d12_ty::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, - u: unsafe { mem::zeroed() }, - }; - let mut dst_location = d3d12_ty::D3D12_TEXTURE_COPY_LOCATION { - pResource: dst.resource.as_mut_ptr(), - Type: d3d12_ty::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, - u: unsafe { mem::zeroed() }, - }; for r in regions { - let src_box = make_box(&r.src_base.origin, &r.size); - unsafe { - *src_location.u.SubresourceIndex_mut() = src.calc_subresource_for_copy(&r.src_base) + let src_location = Direct3D12::D3D12_TEXTURE_COPY_LOCATION { + pResource: unsafe { borrow_interface_temporarily(&src.resource) }, + Type: Direct3D12::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + Anonymous: Direct3D12::D3D12_TEXTURE_COPY_LOCATION_0 { + SubresourceIndex: src.calc_subresource_for_copy(&r.src_base), + }, }; - unsafe { - *dst_location.u.SubresourceIndex_mut() = dst.calc_subresource_for_copy(&r.dst_base) + let dst_location = Direct3D12::D3D12_TEXTURE_COPY_LOCATION { + pResource: unsafe { borrow_interface_temporarily(&dst.resource) }, + Type: Direct3D12::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + Anonymous: Direct3D12::D3D12_TEXTURE_COPY_LOCATION_0 { + SubresourceIndex: dst.calc_subresource_for_copy(&r.dst_base), + }, }; + let src_box = make_box(&r.src_base.origin, &r.size); + unsafe { list.CopyTextureRegion( &dst_location, @@ -531,7 +541,7 @@ impl crate::CommandEncoder for super::CommandEncoder { r.dst_base.origin.y, r.dst_base.origin.z, &src_location, - &src_box, + Some(&src_box), ) }; } @@ -546,25 +556,23 @@ impl crate::CommandEncoder for super::CommandEncoder { T: Iterator, { let list = self.list.as_ref().unwrap(); - let mut src_location = d3d12_ty::D3D12_TEXTURE_COPY_LOCATION { - pResource: src.resource.as_mut_ptr(), - Type: d3d12_ty::D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, - u: unsafe { mem::zeroed() }, - }; - let mut dst_location = d3d12_ty::D3D12_TEXTURE_COPY_LOCATION { - pResource: dst.resource.as_mut_ptr(), - Type: d3d12_ty::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, - u: unsafe { mem::zeroed() }, - }; for r in regions { - let src_box = make_box(&wgt::Origin3d::ZERO, &r.size); - unsafe { - *src_location.u.PlacedFootprint_mut() = r.to_subresource_footprint(dst.format) + let src_location = Direct3D12::D3D12_TEXTURE_COPY_LOCATION { + pResource: unsafe { borrow_interface_temporarily(&src.resource) }, + Type: Direct3D12::D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, + Anonymous: Direct3D12::D3D12_TEXTURE_COPY_LOCATION_0 { + PlacedFootprint: r.to_subresource_footprint(dst.format), + }, }; - unsafe { - *dst_location.u.SubresourceIndex_mut() = - dst.calc_subresource_for_copy(&r.texture_base) + let dst_location = Direct3D12::D3D12_TEXTURE_COPY_LOCATION { + pResource: unsafe { borrow_interface_temporarily(&dst.resource) }, + Type: Direct3D12::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + Anonymous: Direct3D12::D3D12_TEXTURE_COPY_LOCATION_0 { + SubresourceIndex: dst.calc_subresource_for_copy(&r.texture_base), + }, }; + + let src_box = make_box(&wgt::Origin3d::ZERO, &r.size); unsafe { list.CopyTextureRegion( &dst_location, @@ -572,7 +580,7 @@ impl crate::CommandEncoder for super::CommandEncoder { r.texture_base.origin.y, r.texture_base.origin.z, &src_location, - &src_box, + Some(&src_box), ) }; } @@ -588,26 +596,26 @@ impl crate::CommandEncoder for super::CommandEncoder { T: Iterator, { let list = self.list.as_ref().unwrap(); - let mut src_location = d3d12_ty::D3D12_TEXTURE_COPY_LOCATION { - pResource: src.resource.as_mut_ptr(), - Type: d3d12_ty::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, - u: unsafe { mem::zeroed() }, - }; - let mut dst_location = d3d12_ty::D3D12_TEXTURE_COPY_LOCATION { - pResource: dst.resource.as_mut_ptr(), - Type: d3d12_ty::D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, - u: unsafe { mem::zeroed() }, - }; for r in regions { - let src_box = make_box(&r.texture_base.origin, &r.size); - unsafe { - *src_location.u.SubresourceIndex_mut() = - src.calc_subresource_for_copy(&r.texture_base) + let src_location = Direct3D12::D3D12_TEXTURE_COPY_LOCATION { + pResource: unsafe { borrow_interface_temporarily(&src.resource) }, + Type: Direct3D12::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + Anonymous: Direct3D12::D3D12_TEXTURE_COPY_LOCATION_0 { + SubresourceIndex: src.calc_subresource_for_copy(&r.texture_base), + }, }; + let dst_location = Direct3D12::D3D12_TEXTURE_COPY_LOCATION { + pResource: unsafe { borrow_interface_temporarily(&dst.resource) }, + Type: Direct3D12::D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, + Anonymous: Direct3D12::D3D12_TEXTURE_COPY_LOCATION_0 { + PlacedFootprint: r.to_subresource_footprint(src.format), + }, + }; + + let src_box = make_box(&r.texture_base.origin, &r.size); unsafe { - *dst_location.u.PlacedFootprint_mut() = r.to_subresource_footprint(src.format) + list.CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, Some(&src_box)) }; - unsafe { list.CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box) }; } } @@ -616,7 +624,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.list .as_ref() .unwrap() - .BeginQuery(set.raw.as_mut_ptr(), set.raw_ty, index) + .BeginQuery(&set.raw, set.raw_ty, index) }; } unsafe fn end_query(&mut self, set: &super::QuerySet, index: u32) { @@ -624,14 +632,14 @@ impl crate::CommandEncoder for super::CommandEncoder { self.list .as_ref() .unwrap() - .EndQuery(set.raw.as_mut_ptr(), set.raw_ty, index) + .EndQuery(&set.raw, set.raw_ty, index) }; } unsafe fn write_timestamp(&mut self, set: &super::QuerySet, index: u32) { unsafe { self.list.as_ref().unwrap().EndQuery( - set.raw.as_mut_ptr(), - d3d12_ty::D3D12_QUERY_TYPE_TIMESTAMP, + &set.raw, + Direct3D12::D3D12_QUERY_TYPE_TIMESTAMP, index, ) }; @@ -649,11 +657,11 @@ impl crate::CommandEncoder for super::CommandEncoder { ) { unsafe { self.list.as_ref().unwrap().ResolveQueryData( - set.raw.as_mut_ptr(), + &set.raw, set.raw_ty, range.start, range.end - range.start, - buffer.resource.as_mut_ptr(), + &buffer.resource, offset, ) }; @@ -679,7 +687,8 @@ impl crate::CommandEncoder for super::CommandEncoder { .map(|index| (timestamp_writes.query_set.raw.clone(), index)); } - let mut color_views = [d3d12::CpuDescriptor { ptr: 0 }; crate::MAX_COLOR_ATTACHMENTS]; + let mut color_views = + [Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 }; crate::MAX_COLOR_ATTACHMENTS]; for (rtv, cat) in color_views.iter_mut().zip(desc.color_attachments.iter()) { if let Some(cat) = cat.as_ref() { *rtv = cat.target.view.handle_rtv.unwrap().raw; @@ -688,24 +697,22 @@ impl crate::CommandEncoder for super::CommandEncoder { } } - let ds_view = match desc.depth_stencil_attachment { - None => ptr::null(), - Some(ref ds) => { - if ds.target.usage == crate::TextureUses::DEPTH_STENCIL_WRITE { - &ds.target.view.handle_dsv_rw.as_ref().unwrap().raw - } else { - &ds.target.view.handle_dsv_ro.as_ref().unwrap().raw - } + let ds_view = desc.depth_stencil_attachment.as_ref().map(|ds| { + if ds.target.usage == crate::TextureUses::DEPTH_STENCIL_WRITE { + ds.target.view.handle_dsv_rw.as_ref().unwrap().raw + } else { + ds.target.view.handle_dsv_ro.as_ref().unwrap().raw } - }; + }); let list = self.list.as_ref().unwrap(); + #[allow(trivial_casts)] // No other clean way to write the coercion inside .map() below? unsafe { list.OMSetRenderTargets( desc.color_attachments.len() as u32, - color_views.as_ptr(), - 0, - ds_view, + Some(color_views.as_ptr()), + false, + ds_view.as_ref().map(std::ptr::from_ref), ) }; @@ -719,7 +726,7 @@ impl crate::CommandEncoder for super::CommandEncoder { cat.clear_value.b as f32, cat.clear_value.a as f32, ]; - list.clear_render_target_view(*rtv, value, &[]); + unsafe { list.ClearRenderTargetView(*rtv, &value, None) }; } if let Some(ref target) = cat.resolve_target { self.pass.resolves.push(super::PassResolve { @@ -732,31 +739,46 @@ impl crate::CommandEncoder for super::CommandEncoder { } if let Some(ref ds) = desc.depth_stencil_attachment { - let mut flags = d3d12::ClearFlags::empty(); + let mut flags = Direct3D12::D3D12_CLEAR_FLAGS::default(); let aspects = ds.target.view.aspects; if !ds.depth_ops.contains(crate::AttachmentOps::LOAD) && aspects.contains(crate::FormatAspects::DEPTH) { - flags |= d3d12::ClearFlags::DEPTH; + flags |= Direct3D12::D3D12_CLEAR_FLAG_DEPTH; } if !ds.stencil_ops.contains(crate::AttachmentOps::LOAD) && aspects.contains(crate::FormatAspects::STENCIL) { - flags |= d3d12::ClearFlags::STENCIL; + flags |= Direct3D12::D3D12_CLEAR_FLAG_STENCIL; } - if !ds_view.is_null() && !flags.is_empty() { - list.clear_depth_stencil_view( - unsafe { *ds_view }, - flags, - ds.clear_value.0, - ds.clear_value.1 as u8, - &[], - ); + if let Some(ds_view) = ds_view { + if flags != Direct3D12::D3D12_CLEAR_FLAGS::default() { + unsafe { + // list.ClearDepthStencilView( + // ds_view, + // flags, + // ds.clear_value.0, + // ds.clear_value.1 as u8, + // None, + // ) + // TODO: Replace with the above in the next breaking windows-rs release, + // when https://github.com/microsoft/win32metadata/pull/1971 is in. + (windows_core::Interface::vtable(list).ClearDepthStencilView)( + windows_core::Interface::as_raw(list), + ds_view, + flags, + ds.clear_value.0, + ds.clear_value.1 as u8, + 0, + std::ptr::null(), + ) + } + } } } - let raw_vp = d3d12_ty::D3D12_VIEWPORT { + let raw_vp = Direct3D12::D3D12_VIEWPORT { TopLeftX: 0.0, TopLeftY: 0.0, Width: desc.extent.width as f32, @@ -764,14 +786,14 @@ impl crate::CommandEncoder for super::CommandEncoder { MinDepth: 0.0, MaxDepth: 1.0, }; - let raw_rect = d3d12_ty::D3D12_RECT { + let raw_rect = Foundation::RECT { left: 0, top: 0, right: desc.extent.width as i32, bottom: desc.extent.height as i32, }; - unsafe { list.RSSetViewports(1, &raw_vp) }; - unsafe { list.RSSetScissorRects(1, &raw_rect) }; + unsafe { list.RSSetViewports(std::slice::from_ref(&raw_vp)) }; + unsafe { list.RSSetScissorRects(std::slice::from_ref(&raw_rect)) }; } unsafe fn end_render_pass(&mut self) { @@ -782,50 +804,54 @@ impl crate::CommandEncoder for super::CommandEncoder { // All the targets are expected to be in `COLOR_TARGET` state, // but D3D12 has special source/destination states for the resolves. for resolve in self.pass.resolves.iter() { - let mut barrier = d3d12_ty::D3D12_RESOURCE_BARRIER { - Type: d3d12_ty::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, - Flags: d3d12_ty::D3D12_RESOURCE_BARRIER_FLAG_NONE, - u: unsafe { mem::zeroed() }, - }; - //Note: this assumes `D3D12_RESOURCE_STATE_RENDER_TARGET`. - // If it's not the case, we can include the `TextureUses` in `PassResove`. - unsafe { - *barrier.u.Transition_mut() = d3d12_ty::D3D12_RESOURCE_TRANSITION_BARRIER { - pResource: resolve.src.0.as_mut_ptr(), - Subresource: resolve.src.1, - StateBefore: d3d12_ty::D3D12_RESOURCE_STATE_RENDER_TARGET, - StateAfter: d3d12_ty::D3D12_RESOURCE_STATE_RESOLVE_SOURCE, - } + let barrier = Direct3D12::D3D12_RESOURCE_BARRIER { + Type: Direct3D12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + Flags: Direct3D12::D3D12_RESOURCE_BARRIER_FLAG_NONE, + Anonymous: Direct3D12::D3D12_RESOURCE_BARRIER_0 { + // Note: this assumes `D3D12_RESOURCE_STATE_RENDER_TARGET`. + // If it's not the case, we can include the `TextureUses` in `PassResove`. + Transition: mem::ManuallyDrop::new( + Direct3D12::D3D12_RESOURCE_TRANSITION_BARRIER { + pResource: unsafe { borrow_interface_temporarily(&resolve.src.0) }, + Subresource: resolve.src.1, + StateBefore: Direct3D12::D3D12_RESOURCE_STATE_RENDER_TARGET, + StateAfter: Direct3D12::D3D12_RESOURCE_STATE_RESOLVE_SOURCE, + }, + ), + }, }; self.temp.barriers.push(barrier); - unsafe { - *barrier.u.Transition_mut() = d3d12_ty::D3D12_RESOURCE_TRANSITION_BARRIER { - pResource: resolve.dst.0.as_mut_ptr(), - Subresource: resolve.dst.1, - StateBefore: d3d12_ty::D3D12_RESOURCE_STATE_RENDER_TARGET, - StateAfter: d3d12_ty::D3D12_RESOURCE_STATE_RESOLVE_DEST, - } + let barrier = Direct3D12::D3D12_RESOURCE_BARRIER { + Type: Direct3D12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + Flags: Direct3D12::D3D12_RESOURCE_BARRIER_FLAG_NONE, + Anonymous: Direct3D12::D3D12_RESOURCE_BARRIER_0 { + // Note: this assumes `D3D12_RESOURCE_STATE_RENDER_TARGET`. + // If it's not the case, we can include the `TextureUses` in `PassResolve`. + Transition: mem::ManuallyDrop::new( + Direct3D12::D3D12_RESOURCE_TRANSITION_BARRIER { + pResource: unsafe { borrow_interface_temporarily(&resolve.dst.0) }, + Subresource: resolve.dst.1, + StateBefore: Direct3D12::D3D12_RESOURCE_STATE_RENDER_TARGET, + StateAfter: Direct3D12::D3D12_RESOURCE_STATE_RESOLVE_DEST, + }, + ), + }, }; self.temp.barriers.push(barrier); } if !self.temp.barriers.is_empty() { profiling::scope!("ID3D12GraphicsCommandList::ResourceBarrier"); - unsafe { - list.ResourceBarrier( - self.temp.barriers.len() as u32, - self.temp.barriers.as_ptr(), - ) - }; + unsafe { list.ResourceBarrier(&self.temp.barriers) }; } for resolve in self.pass.resolves.iter() { profiling::scope!("ID3D12GraphicsCommandList::ResolveSubresource"); unsafe { list.ResolveSubresource( - resolve.dst.0.as_mut_ptr(), + &resolve.dst.0, resolve.dst.1, - resolve.src.0.as_mut_ptr(), + &resolve.src.0, resolve.src.1, resolve.format, ) @@ -834,17 +860,12 @@ impl crate::CommandEncoder for super::CommandEncoder { // Flip all the barriers to reverse, back into `COLOR_TARGET`. for barrier in self.temp.barriers.iter_mut() { - let transition = unsafe { barrier.u.Transition_mut() }; + let transition = unsafe { &mut *barrier.Anonymous.Transition }; mem::swap(&mut transition.StateBefore, &mut transition.StateAfter); } if !self.temp.barriers.is_empty() { profiling::scope!("ID3D12GraphicsCommandList::ResourceBarrier"); - unsafe { - list.ResourceBarrier( - self.temp.barriers.len() as u32, - self.temp.barriers.as_ptr(), - ) - }; + unsafe { list.ResourceBarrier(&self.temp.barriers) }; } } @@ -886,7 +907,9 @@ impl crate::CommandEncoder for super::CommandEncoder { { self.pass.root_elements[root_index] = super::RootElement::DynamicOffsetBuffer { kind, - address: gpu_base + offset as d3d12::GpuAddress, + address: Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE { + ptr: gpu_base.ptr + offset as u64, + }, }; root_index += 1; } @@ -927,7 +950,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.list .as_ref() .unwrap() - .SetMarker(0, wide_label.as_ptr().cast(), size) + .SetMarker(0, Some(wide_label.as_ptr().cast()), size) }; } unsafe fn begin_debug_marker(&mut self, group_label: &str) { @@ -936,7 +959,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.list .as_ref() .unwrap() - .BeginEvent(0, wide_label.as_ptr().cast(), size) + .BeginEvent(0, Some(wide_label.as_ptr().cast()), size) }; } unsafe fn end_debug_marker(&mut self) { @@ -944,15 +967,15 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) { - let list = self.list.as_ref().unwrap().clone(); + let list = self.list.clone().unwrap(); if self.pass.layout.signature != pipeline.layout.signature { // D3D12 requires full reset on signature change - list.set_graphics_root_signature(&pipeline.layout.signature); + unsafe { list.SetGraphicsRootSignature(pipeline.layout.signature.as_ref()) }; self.reset_signature(&pipeline.layout); }; - list.set_pipeline_state(&pipeline.raw); + unsafe { list.SetPipelineState(&pipeline.raw) }; unsafe { list.IASetPrimitiveTopology(pipeline.topology) }; for (index, (vb, &stride)) in self @@ -976,11 +999,13 @@ impl crate::CommandEncoder for super::CommandEncoder { binding: crate::BufferBinding<'a, super::Buffer>, format: wgt::IndexFormat, ) { - self.list.as_ref().unwrap().set_index_buffer( - binding.resolve_address(), - binding.resolve_size() as u32, - auxil::dxgi::conv::map_index_format(format), - ); + let ibv = Direct3D12::D3D12_INDEX_BUFFER_VIEW { + BufferLocation: binding.resolve_address(), + SizeInBytes: binding.resolve_size() as u32, + Format: auxil::dxgi::conv::map_index_format(format), + }; + + unsafe { self.list.as_ref().unwrap().IASetIndexBuffer(Some(&ibv)) } } unsafe fn set_vertex_buffer<'a>( &mut self, @@ -994,7 +1019,7 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn set_viewport(&mut self, rect: &crate::Rect, depth_range: Range) { - let raw_vp = d3d12_ty::D3D12_VIEWPORT { + let raw_vp = Direct3D12::D3D12_VIEWPORT { TopLeftX: rect.x, TopLeftY: rect.y, Width: rect.w, @@ -1002,22 +1027,32 @@ impl crate::CommandEncoder for super::CommandEncoder { MinDepth: depth_range.start, MaxDepth: depth_range.end, }; - unsafe { self.list.as_ref().unwrap().RSSetViewports(1, &raw_vp) }; + unsafe { + self.list + .as_ref() + .unwrap() + .RSSetViewports(std::slice::from_ref(&raw_vp)) + } } unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect) { - let raw_rect = d3d12_ty::D3D12_RECT { + let raw_rect = Foundation::RECT { left: rect.x as i32, top: rect.y as i32, right: (rect.x + rect.w) as i32, bottom: (rect.y + rect.h) as i32, }; - unsafe { self.list.as_ref().unwrap().RSSetScissorRects(1, &raw_rect) }; + unsafe { + self.list + .as_ref() + .unwrap() + .RSSetScissorRects(std::slice::from_ref(&raw_rect)) + } } unsafe fn set_stencil_reference(&mut self, value: u32) { - self.list.as_ref().unwrap().set_stencil_reference(value); + unsafe { self.list.as_ref().unwrap().OMSetStencilRef(value) } } unsafe fn set_blend_constants(&mut self, color: &[f32; 4]) { - self.list.as_ref().unwrap().set_blend_factor(*color); + unsafe { self.list.as_ref().unwrap().OMSetBlendFactor(Some(color)) } } unsafe fn draw( @@ -1028,12 +1063,14 @@ impl crate::CommandEncoder for super::CommandEncoder { instance_count: u32, ) { unsafe { self.prepare_draw(first_vertex as i32, first_instance) }; - self.list.as_ref().unwrap().draw( - vertex_count, - instance_count, - first_vertex, - first_instance, - ); + unsafe { + self.list.as_ref().unwrap().DrawInstanced( + vertex_count, + instance_count, + first_vertex, + first_instance, + ) + } } unsafe fn draw_indexed( &mut self, @@ -1044,13 +1081,15 @@ impl crate::CommandEncoder for super::CommandEncoder { instance_count: u32, ) { unsafe { self.prepare_draw(base_vertex, first_instance) }; - self.list.as_ref().unwrap().draw_indexed( - index_count, - instance_count, - first_index, - base_vertex, - first_instance, - ); + unsafe { + self.list.as_ref().unwrap().DrawIndexedInstanced( + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + ) + } } unsafe fn draw_indirect( &mut self, @@ -1061,14 +1100,14 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe { self.prepare_draw(0, 0) }; unsafe { self.list.as_ref().unwrap().ExecuteIndirect( - self.shared.cmd_signatures.draw.as_mut_ptr(), + &self.shared.cmd_signatures.draw, draw_count, - buffer.resource.as_mut_ptr(), + &buffer.resource, offset, - ptr::null_mut(), + None, 0, ) - }; + } } unsafe fn draw_indexed_indirect( &mut self, @@ -1079,14 +1118,14 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe { self.prepare_draw(0, 0) }; unsafe { self.list.as_ref().unwrap().ExecuteIndirect( - self.shared.cmd_signatures.draw_indexed.as_mut_ptr(), + &self.shared.cmd_signatures.draw_indexed, draw_count, - buffer.resource.as_mut_ptr(), + &buffer.resource, offset, - ptr::null_mut(), + None, 0, ) - }; + } } unsafe fn draw_indirect_count( &mut self, @@ -1099,14 +1138,14 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe { self.prepare_draw(0, 0) }; unsafe { self.list.as_ref().unwrap().ExecuteIndirect( - self.shared.cmd_signatures.draw.as_mut_ptr(), + &self.shared.cmd_signatures.draw, max_count, - buffer.resource.as_mut_ptr(), + &buffer.resource, offset, - count_buffer.resource.as_mut_ptr(), + &count_buffer.resource, count_offset, ) - }; + } } unsafe fn draw_indexed_indirect_count( &mut self, @@ -1119,14 +1158,14 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe { self.prepare_draw(0, 0) }; unsafe { self.list.as_ref().unwrap().ExecuteIndirect( - self.shared.cmd_signatures.draw_indexed.as_mut_ptr(), + &self.shared.cmd_signatures.draw_indexed, max_count, - buffer.resource.as_mut_ptr(), + &buffer.resource, offset, - count_buffer.resource.as_mut_ptr(), + &count_buffer.resource, count_offset, ) - }; + } } // compute @@ -1154,34 +1193,35 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { - let list = self.list.as_ref().unwrap().clone(); + let list = self.list.clone().unwrap(); if self.pass.layout.signature != pipeline.layout.signature { // D3D12 requires full reset on signature change - list.set_compute_root_signature(&pipeline.layout.signature); + unsafe { list.SetComputeRootSignature(pipeline.layout.signature.as_ref()) }; self.reset_signature(&pipeline.layout); }; - list.set_pipeline_state(&pipeline.raw); + unsafe { list.SetPipelineState(&pipeline.raw) } } - unsafe fn dispatch(&mut self, count: [u32; 3]) { + unsafe fn dispatch(&mut self, count @ [x, y, z]: [u32; 3]) { self.prepare_dispatch(count); - self.list.as_ref().unwrap().dispatch(count); + unsafe { self.list.as_ref().unwrap().Dispatch(x, y, z) } } + unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) { self.prepare_dispatch([0; 3]); //TODO: update special constants indirectly unsafe { self.list.as_ref().unwrap().ExecuteIndirect( - self.shared.cmd_signatures.dispatch.as_mut_ptr(), + &self.shared.cmd_signatures.dispatch, 1, - buffer.resource.as_mut_ptr(), + &buffer.resource, offset, - ptr::null_mut(), + None, 0, ) - }; + } } unsafe fn build_acceleration_structures<'a, T>( diff --git a/wgpu-hal/src/dx12/conv.rs b/wgpu-hal/src/dx12/conv.rs index b09ea76080..8e60f6e064 100644 --- a/wgpu-hal/src/dx12/conv.rs +++ b/wgpu-hal/src/dx12/conv.rs @@ -1,79 +1,75 @@ -use std::iter; -use winapi::{ - shared::minwindef::BOOL, - um::{d3d12 as d3d12_ty, d3dcommon}, -}; +use windows::Win32::Graphics::{Direct3D, Direct3D12}; pub fn map_buffer_usage_to_resource_flags( usage: crate::BufferUses, -) -> d3d12_ty::D3D12_RESOURCE_FLAGS { - let mut flags = 0; +) -> Direct3D12::D3D12_RESOURCE_FLAGS { + let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE; if usage.contains(crate::BufferUses::STORAGE_READ_WRITE) { - flags |= d3d12_ty::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } flags } -pub fn map_texture_dimension(dim: wgt::TextureDimension) -> d3d12_ty::D3D12_RESOURCE_DIMENSION { +pub fn map_texture_dimension(dim: wgt::TextureDimension) -> Direct3D12::D3D12_RESOURCE_DIMENSION { match dim { - wgt::TextureDimension::D1 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE1D, - wgt::TextureDimension::D2 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE2D, - wgt::TextureDimension::D3 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE3D, + wgt::TextureDimension::D1 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE1D, + wgt::TextureDimension::D2 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE2D, + wgt::TextureDimension::D3 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE3D, } } pub fn map_texture_usage_to_resource_flags( usage: crate::TextureUses, -) -> d3d12_ty::D3D12_RESOURCE_FLAGS { - let mut flags = 0; +) -> Direct3D12::D3D12_RESOURCE_FLAGS { + let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE; if usage.contains(crate::TextureUses::COLOR_TARGET) { - flags |= d3d12_ty::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; } if usage.intersects( crate::TextureUses::DEPTH_STENCIL_READ | crate::TextureUses::DEPTH_STENCIL_WRITE, ) { - flags |= d3d12_ty::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; if !usage.contains(crate::TextureUses::RESOURCE) { - flags |= d3d12_ty::D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; + flags |= Direct3D12::D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; } } if usage.contains(crate::TextureUses::STORAGE_READ_WRITE) { - flags |= d3d12_ty::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } flags } -pub fn map_address_mode(mode: wgt::AddressMode) -> d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE { +pub fn map_address_mode(mode: wgt::AddressMode) -> Direct3D12::D3D12_TEXTURE_ADDRESS_MODE { use wgt::AddressMode as Am; match mode { - Am::Repeat => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_WRAP, - Am::MirrorRepeat => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_MIRROR, - Am::ClampToEdge => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_CLAMP, - Am::ClampToBorder => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_BORDER, - //Am::MirrorClamp => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE, + Am::Repeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_WRAP, + Am::MirrorRepeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR, + Am::ClampToEdge => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_CLAMP, + Am::ClampToBorder => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_BORDER, + //Am::MirrorClamp => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE, } } -pub fn map_filter_mode(mode: wgt::FilterMode) -> d3d12_ty::D3D12_FILTER_TYPE { +pub fn map_filter_mode(mode: wgt::FilterMode) -> Direct3D12::D3D12_FILTER_TYPE { match mode { - wgt::FilterMode::Nearest => d3d12_ty::D3D12_FILTER_TYPE_POINT, - wgt::FilterMode::Linear => d3d12_ty::D3D12_FILTER_TYPE_LINEAR, + wgt::FilterMode::Nearest => Direct3D12::D3D12_FILTER_TYPE_POINT, + wgt::FilterMode::Linear => Direct3D12::D3D12_FILTER_TYPE_LINEAR, } } -pub fn map_comparison(func: wgt::CompareFunction) -> d3d12_ty::D3D12_COMPARISON_FUNC { +pub fn map_comparison(func: wgt::CompareFunction) -> Direct3D12::D3D12_COMPARISON_FUNC { use wgt::CompareFunction as Cf; match func { - Cf::Never => d3d12_ty::D3D12_COMPARISON_FUNC_NEVER, - Cf::Less => d3d12_ty::D3D12_COMPARISON_FUNC_LESS, - Cf::LessEqual => d3d12_ty::D3D12_COMPARISON_FUNC_LESS_EQUAL, - Cf::Equal => d3d12_ty::D3D12_COMPARISON_FUNC_EQUAL, - Cf::GreaterEqual => d3d12_ty::D3D12_COMPARISON_FUNC_GREATER_EQUAL, - Cf::Greater => d3d12_ty::D3D12_COMPARISON_FUNC_GREATER, - Cf::NotEqual => d3d12_ty::D3D12_COMPARISON_FUNC_NOT_EQUAL, - Cf::Always => d3d12_ty::D3D12_COMPARISON_FUNC_ALWAYS, + Cf::Never => Direct3D12::D3D12_COMPARISON_FUNC_NEVER, + Cf::Less => Direct3D12::D3D12_COMPARISON_FUNC_LESS, + Cf::LessEqual => Direct3D12::D3D12_COMPARISON_FUNC_LESS_EQUAL, + Cf::Equal => Direct3D12::D3D12_COMPARISON_FUNC_EQUAL, + Cf::GreaterEqual => Direct3D12::D3D12_COMPARISON_FUNC_GREATER_EQUAL, + Cf::Greater => Direct3D12::D3D12_COMPARISON_FUNC_GREATER, + Cf::NotEqual => Direct3D12::D3D12_COMPARISON_FUNC_NOT_EQUAL, + Cf::Always => Direct3D12::D3D12_COMPARISON_FUNC_ALWAYS, } } @@ -86,71 +82,67 @@ pub fn map_border_color(border_color: Option) -> [f32; } } -pub fn map_visibility(visibility: wgt::ShaderStages) -> d3d12::ShaderVisibility { +pub fn map_visibility(visibility: wgt::ShaderStages) -> Direct3D12::D3D12_SHADER_VISIBILITY { match visibility { - wgt::ShaderStages::VERTEX => d3d12::ShaderVisibility::VS, - wgt::ShaderStages::FRAGMENT => d3d12::ShaderVisibility::PS, - _ => d3d12::ShaderVisibility::All, + wgt::ShaderStages::VERTEX => Direct3D12::D3D12_SHADER_VISIBILITY_VERTEX, + wgt::ShaderStages::FRAGMENT => Direct3D12::D3D12_SHADER_VISIBILITY_PIXEL, + _ => Direct3D12::D3D12_SHADER_VISIBILITY_ALL, } } -pub fn map_binding_type(ty: &wgt::BindingType) -> d3d12::DescriptorRangeType { +pub fn map_binding_type(ty: &wgt::BindingType) -> Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE { use wgt::BindingType as Bt; match *ty { - Bt::Sampler { .. } => d3d12::DescriptorRangeType::Sampler, + Bt::Sampler { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, Bt::Buffer { ty: wgt::BufferBindingType::Uniform, .. - } => d3d12::DescriptorRangeType::CBV, + } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV, Bt::Buffer { ty: wgt::BufferBindingType::Storage { read_only: true }, .. } - | Bt::Texture { .. } => d3d12::DescriptorRangeType::SRV, + | Bt::Texture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV, Bt::Buffer { ty: wgt::BufferBindingType::Storage { read_only: false }, .. } - | Bt::StorageTexture { .. } => d3d12::DescriptorRangeType::UAV, + | Bt::StorageTexture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV, Bt::AccelerationStructure => todo!(), } } -pub fn map_label(name: &str) -> Vec { - name.encode_utf16().chain(iter::once(0)).collect() -} - -pub fn map_buffer_usage_to_state(usage: crate::BufferUses) -> d3d12_ty::D3D12_RESOURCE_STATES { +pub fn map_buffer_usage_to_state(usage: crate::BufferUses) -> Direct3D12::D3D12_RESOURCE_STATES { use crate::BufferUses as Bu; - let mut state = d3d12_ty::D3D12_RESOURCE_STATE_COMMON; + let mut state = Direct3D12::D3D12_RESOURCE_STATE_COMMON; if usage.intersects(Bu::COPY_SRC) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_COPY_SOURCE; + state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_SOURCE; } if usage.intersects(Bu::COPY_DST) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_COPY_DEST; + state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_DEST; } if usage.intersects(Bu::INDEX) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_INDEX_BUFFER; + state |= Direct3D12::D3D12_RESOURCE_STATE_INDEX_BUFFER; } if usage.intersects(Bu::VERTEX | Bu::UNIFORM) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; + state |= Direct3D12::D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; } if usage.intersects(Bu::STORAGE_READ_WRITE) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } else if usage.intersects(Bu::STORAGE_READ) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE - | d3d12_ty::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE + | Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; } if usage.intersects(Bu::INDIRECT) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; + state |= Direct3D12::D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; } state } -pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12_ty::D3D12_RESOURCE_STATES { +pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> Direct3D12::D3D12_RESOURCE_STATES { use crate::TextureUses as Tu; - let mut state = d3d12_ty::D3D12_RESOURCE_STATE_COMMON; + let mut state = Direct3D12::D3D12_RESOURCE_STATE_COMMON; //Note: `RESOLVE_SOURCE` and `RESOLVE_DEST` are not used here //Note: `PRESENT` is the same as `COMMON` if usage == crate::TextureUses::UNINITIALIZED { @@ -158,26 +150,26 @@ pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12_ty::D3D12_ } if usage.intersects(Tu::COPY_SRC) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_COPY_SOURCE; + state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_SOURCE; } if usage.intersects(Tu::COPY_DST) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_COPY_DEST; + state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_DEST; } if usage.intersects(Tu::RESOURCE) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE - | d3d12_ty::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE + | Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; } if usage.intersects(Tu::COLOR_TARGET) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_RENDER_TARGET; + state |= Direct3D12::D3D12_RESOURCE_STATE_RENDER_TARGET; } if usage.intersects(Tu::DEPTH_STENCIL_READ) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_DEPTH_READ; + state |= Direct3D12::D3D12_RESOURCE_STATE_DEPTH_READ; } if usage.intersects(Tu::DEPTH_STENCIL_WRITE) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_DEPTH_WRITE; + state |= Direct3D12::D3D12_RESOURCE_STATE_DEPTH_WRITE; } if usage.intersects(Tu::STORAGE_READ | Tu::STORAGE_READ_WRITE) { - state |= d3d12_ty::D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } state } @@ -185,37 +177,37 @@ pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12_ty::D3D12_ pub fn map_topology( topology: wgt::PrimitiveTopology, ) -> ( - d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE, - d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY, + Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE, + Direct3D::D3D_PRIMITIVE_TOPOLOGY, ) { match topology { wgt::PrimitiveTopology::PointList => ( - d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT, - d3dcommon::D3D_PRIMITIVE_TOPOLOGY_POINTLIST, + Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT, + Direct3D::D3D_PRIMITIVE_TOPOLOGY_POINTLIST, ), wgt::PrimitiveTopology::LineList => ( - d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, - d3dcommon::D3D_PRIMITIVE_TOPOLOGY_LINELIST, + Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, + Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINELIST, ), wgt::PrimitiveTopology::LineStrip => ( - d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, - d3dcommon::D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, + Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, + Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, ), wgt::PrimitiveTopology::TriangleList => ( - d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, - d3dcommon::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, + Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, ), wgt::PrimitiveTopology::TriangleStrip => ( - d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, - d3dcommon::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, + Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, ), } } -pub fn map_polygon_mode(mode: wgt::PolygonMode) -> d3d12_ty::D3D12_FILL_MODE { +pub fn map_polygon_mode(mode: wgt::PolygonMode) -> Direct3D12::D3D12_FILL_MODE { match mode { - wgt::PolygonMode::Fill => d3d12_ty::D3D12_FILL_MODE_SOLID, - wgt::PolygonMode::Line => d3d12_ty::D3D12_FILL_MODE_WIREFRAME, + wgt::PolygonMode::Fill => Direct3D12::D3D12_FILL_MODE_SOLID, + wgt::PolygonMode::Line => Direct3D12::D3D12_FILL_MODE_WIREFRAME, wgt::PolygonMode::Point => panic!( "{:?} is not enabled for this backend", wgt::Features::POLYGON_MODE_POINT @@ -227,32 +219,32 @@ pub fn map_polygon_mode(mode: wgt::PolygonMode) -> d3d12_ty::D3D12_FILL_MODE { /// (see ). /// Therefore this function takes an additional `is_alpha` argument /// which if set will return an equivalent `_ALPHA` factor. -fn map_blend_factor(factor: wgt::BlendFactor, is_alpha: bool) -> d3d12_ty::D3D12_BLEND { +fn map_blend_factor(factor: wgt::BlendFactor, is_alpha: bool) -> Direct3D12::D3D12_BLEND { use wgt::BlendFactor as Bf; match factor { - Bf::Zero => d3d12_ty::D3D12_BLEND_ZERO, - Bf::One => d3d12_ty::D3D12_BLEND_ONE, - Bf::Src if is_alpha => d3d12_ty::D3D12_BLEND_SRC_ALPHA, - Bf::Src => d3d12_ty::D3D12_BLEND_SRC_COLOR, - Bf::OneMinusSrc if is_alpha => d3d12_ty::D3D12_BLEND_INV_SRC_ALPHA, - Bf::OneMinusSrc => d3d12_ty::D3D12_BLEND_INV_SRC_COLOR, - Bf::Dst if is_alpha => d3d12_ty::D3D12_BLEND_DEST_ALPHA, - Bf::Dst => d3d12_ty::D3D12_BLEND_DEST_COLOR, - Bf::OneMinusDst if is_alpha => d3d12_ty::D3D12_BLEND_INV_DEST_ALPHA, - Bf::OneMinusDst => d3d12_ty::D3D12_BLEND_INV_DEST_COLOR, - Bf::SrcAlpha => d3d12_ty::D3D12_BLEND_SRC_ALPHA, - Bf::OneMinusSrcAlpha => d3d12_ty::D3D12_BLEND_INV_SRC_ALPHA, - Bf::DstAlpha => d3d12_ty::D3D12_BLEND_DEST_ALPHA, - Bf::OneMinusDstAlpha => d3d12_ty::D3D12_BLEND_INV_DEST_ALPHA, - Bf::Constant => d3d12_ty::D3D12_BLEND_BLEND_FACTOR, - Bf::OneMinusConstant => d3d12_ty::D3D12_BLEND_INV_BLEND_FACTOR, - Bf::SrcAlphaSaturated => d3d12_ty::D3D12_BLEND_SRC_ALPHA_SAT, - Bf::Src1 if is_alpha => d3d12_ty::D3D12_BLEND_SRC1_ALPHA, - Bf::Src1 => d3d12_ty::D3D12_BLEND_SRC1_COLOR, - Bf::OneMinusSrc1 if is_alpha => d3d12_ty::D3D12_BLEND_INV_SRC1_ALPHA, - Bf::OneMinusSrc1 => d3d12_ty::D3D12_BLEND_INV_SRC1_COLOR, - Bf::Src1Alpha => d3d12_ty::D3D12_BLEND_SRC1_ALPHA, - Bf::OneMinusSrc1Alpha => d3d12_ty::D3D12_BLEND_INV_SRC1_ALPHA, + Bf::Zero => Direct3D12::D3D12_BLEND_ZERO, + Bf::One => Direct3D12::D3D12_BLEND_ONE, + Bf::Src if is_alpha => Direct3D12::D3D12_BLEND_SRC_ALPHA, + Bf::Src => Direct3D12::D3D12_BLEND_SRC_COLOR, + Bf::OneMinusSrc if is_alpha => Direct3D12::D3D12_BLEND_INV_SRC_ALPHA, + Bf::OneMinusSrc => Direct3D12::D3D12_BLEND_INV_SRC_COLOR, + Bf::Dst if is_alpha => Direct3D12::D3D12_BLEND_DEST_ALPHA, + Bf::Dst => Direct3D12::D3D12_BLEND_DEST_COLOR, + Bf::OneMinusDst if is_alpha => Direct3D12::D3D12_BLEND_INV_DEST_ALPHA, + Bf::OneMinusDst => Direct3D12::D3D12_BLEND_INV_DEST_COLOR, + Bf::SrcAlpha => Direct3D12::D3D12_BLEND_SRC_ALPHA, + Bf::OneMinusSrcAlpha => Direct3D12::D3D12_BLEND_INV_SRC_ALPHA, + Bf::DstAlpha => Direct3D12::D3D12_BLEND_DEST_ALPHA, + Bf::OneMinusDstAlpha => Direct3D12::D3D12_BLEND_INV_DEST_ALPHA, + Bf::Constant => Direct3D12::D3D12_BLEND_BLEND_FACTOR, + Bf::OneMinusConstant => Direct3D12::D3D12_BLEND_INV_BLEND_FACTOR, + Bf::SrcAlphaSaturated => Direct3D12::D3D12_BLEND_SRC_ALPHA_SAT, + Bf::Src1 if is_alpha => Direct3D12::D3D12_BLEND_SRC1_ALPHA, + Bf::Src1 => Direct3D12::D3D12_BLEND_SRC1_COLOR, + Bf::OneMinusSrc1 if is_alpha => Direct3D12::D3D12_BLEND_INV_SRC1_ALPHA, + Bf::OneMinusSrc1 => Direct3D12::D3D12_BLEND_INV_SRC1_COLOR, + Bf::Src1Alpha => Direct3D12::D3D12_BLEND_SRC1_ALPHA, + Bf::OneMinusSrc1Alpha => Direct3D12::D3D12_BLEND_INV_SRC1_ALPHA, } } @@ -260,16 +252,16 @@ fn map_blend_component( component: &wgt::BlendComponent, is_alpha: bool, ) -> ( - d3d12_ty::D3D12_BLEND_OP, - d3d12_ty::D3D12_BLEND, - d3d12_ty::D3D12_BLEND, + Direct3D12::D3D12_BLEND_OP, + Direct3D12::D3D12_BLEND, + Direct3D12::D3D12_BLEND, ) { let raw_op = match component.operation { - wgt::BlendOperation::Add => d3d12_ty::D3D12_BLEND_OP_ADD, - wgt::BlendOperation::Subtract => d3d12_ty::D3D12_BLEND_OP_SUBTRACT, - wgt::BlendOperation::ReverseSubtract => d3d12_ty::D3D12_BLEND_OP_REV_SUBTRACT, - wgt::BlendOperation::Min => d3d12_ty::D3D12_BLEND_OP_MIN, - wgt::BlendOperation::Max => d3d12_ty::D3D12_BLEND_OP_MAX, + wgt::BlendOperation::Add => Direct3D12::D3D12_BLEND_OP_ADD, + wgt::BlendOperation::Subtract => Direct3D12::D3D12_BLEND_OP_SUBTRACT, + wgt::BlendOperation::ReverseSubtract => Direct3D12::D3D12_BLEND_OP_REV_SUBTRACT, + wgt::BlendOperation::Min => Direct3D12::D3D12_BLEND_OP_MIN, + wgt::BlendOperation::Max => Direct3D12::D3D12_BLEND_OP_MAX, }; let raw_src = map_blend_factor(component.src_factor, is_alpha); let raw_dst = map_blend_factor(component.dst_factor, is_alpha); @@ -278,21 +270,22 @@ fn map_blend_component( pub fn map_render_targets( color_targets: &[Option], -) -> [d3d12_ty::D3D12_RENDER_TARGET_BLEND_DESC; - d3d12_ty::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] { - let dummy_target = d3d12_ty::D3D12_RENDER_TARGET_BLEND_DESC { - BlendEnable: 0, - LogicOpEnable: 0, - SrcBlend: d3d12_ty::D3D12_BLEND_ZERO, - DestBlend: d3d12_ty::D3D12_BLEND_ZERO, - BlendOp: d3d12_ty::D3D12_BLEND_OP_ADD, - SrcBlendAlpha: d3d12_ty::D3D12_BLEND_ZERO, - DestBlendAlpha: d3d12_ty::D3D12_BLEND_ZERO, - BlendOpAlpha: d3d12_ty::D3D12_BLEND_OP_ADD, - LogicOp: d3d12_ty::D3D12_LOGIC_OP_CLEAR, +) -> [Direct3D12::D3D12_RENDER_TARGET_BLEND_DESC; + Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] { + let dummy_target = Direct3D12::D3D12_RENDER_TARGET_BLEND_DESC { + BlendEnable: false.into(), + LogicOpEnable: false.into(), + SrcBlend: Direct3D12::D3D12_BLEND_ZERO, + DestBlend: Direct3D12::D3D12_BLEND_ZERO, + BlendOp: Direct3D12::D3D12_BLEND_OP_ADD, + SrcBlendAlpha: Direct3D12::D3D12_BLEND_ZERO, + DestBlendAlpha: Direct3D12::D3D12_BLEND_ZERO, + BlendOpAlpha: Direct3D12::D3D12_BLEND_OP_ADD, + LogicOp: Direct3D12::D3D12_LOGIC_OP_CLEAR, RenderTargetWriteMask: 0, }; - let mut raw_targets = [dummy_target; d3d12_ty::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize]; + let mut raw_targets = + [dummy_target; Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize]; for (raw, ct) in raw_targets.iter_mut().zip(color_targets.iter()) { if let Some(ct) = ct.as_ref() { @@ -300,7 +293,7 @@ pub fn map_render_targets( if let Some(ref blend) = ct.blend { let (color_op, color_src, color_dst) = map_blend_component(&blend.color, false); let (alpha_op, alpha_src, alpha_dst) = map_blend_component(&blend.alpha, true); - raw.BlendEnable = 1; + raw.BlendEnable = true.into(); raw.BlendOp = color_op; raw.SrcBlend = color_src; raw.DestBlend = color_dst; @@ -314,22 +307,22 @@ pub fn map_render_targets( raw_targets } -fn map_stencil_op(op: wgt::StencilOperation) -> d3d12_ty::D3D12_STENCIL_OP { +fn map_stencil_op(op: wgt::StencilOperation) -> Direct3D12::D3D12_STENCIL_OP { use wgt::StencilOperation as So; match op { - So::Keep => d3d12_ty::D3D12_STENCIL_OP_KEEP, - So::Zero => d3d12_ty::D3D12_STENCIL_OP_ZERO, - So::Replace => d3d12_ty::D3D12_STENCIL_OP_REPLACE, - So::IncrementClamp => d3d12_ty::D3D12_STENCIL_OP_INCR_SAT, - So::IncrementWrap => d3d12_ty::D3D12_STENCIL_OP_INCR, - So::DecrementClamp => d3d12_ty::D3D12_STENCIL_OP_DECR_SAT, - So::DecrementWrap => d3d12_ty::D3D12_STENCIL_OP_DECR, - So::Invert => d3d12_ty::D3D12_STENCIL_OP_INVERT, + So::Keep => Direct3D12::D3D12_STENCIL_OP_KEEP, + So::Zero => Direct3D12::D3D12_STENCIL_OP_ZERO, + So::Replace => Direct3D12::D3D12_STENCIL_OP_REPLACE, + So::IncrementClamp => Direct3D12::D3D12_STENCIL_OP_INCR_SAT, + So::IncrementWrap => Direct3D12::D3D12_STENCIL_OP_INCR, + So::DecrementClamp => Direct3D12::D3D12_STENCIL_OP_DECR_SAT, + So::DecrementWrap => Direct3D12::D3D12_STENCIL_OP_DECR, + So::Invert => Direct3D12::D3D12_STENCIL_OP_INVERT, } } -fn map_stencil_face(face: &wgt::StencilFaceState) -> d3d12_ty::D3D12_DEPTH_STENCILOP_DESC { - d3d12_ty::D3D12_DEPTH_STENCILOP_DESC { +fn map_stencil_face(face: &wgt::StencilFaceState) -> Direct3D12::D3D12_DEPTH_STENCILOP_DESC { + Direct3D12::D3D12_DEPTH_STENCILOP_DESC { StencilFailOp: map_stencil_op(face.fail_op), StencilDepthFailOp: map_stencil_op(face.depth_fail_op), StencilPassOp: map_stencil_op(face.pass_op), @@ -337,16 +330,16 @@ fn map_stencil_face(face: &wgt::StencilFaceState) -> d3d12_ty::D3D12_DEPTH_STENC } } -pub fn map_depth_stencil(ds: &wgt::DepthStencilState) -> d3d12_ty::D3D12_DEPTH_STENCIL_DESC { - d3d12_ty::D3D12_DEPTH_STENCIL_DESC { - DepthEnable: BOOL::from(ds.is_depth_enabled()), +pub fn map_depth_stencil(ds: &wgt::DepthStencilState) -> Direct3D12::D3D12_DEPTH_STENCIL_DESC { + Direct3D12::D3D12_DEPTH_STENCIL_DESC { + DepthEnable: ds.is_depth_enabled().into(), DepthWriteMask: if ds.depth_write_enabled { - d3d12_ty::D3D12_DEPTH_WRITE_MASK_ALL + Direct3D12::D3D12_DEPTH_WRITE_MASK_ALL } else { - d3d12_ty::D3D12_DEPTH_WRITE_MASK_ZERO + Direct3D12::D3D12_DEPTH_WRITE_MASK_ZERO }, DepthFunc: map_comparison(ds.depth_compare), - StencilEnable: BOOL::from(ds.stencil.is_enabled()), + StencilEnable: ds.stencil.is_enabled().into(), StencilReadMask: ds.stencil.read_mask as u8, StencilWriteMask: ds.stencil.write_mask as u8, FrontFace: map_stencil_face(&ds.stencil.front), diff --git a/wgpu-hal/src/dx12/descriptor.rs b/wgpu-hal/src/dx12/descriptor.rs index 6f7afe8071..f3b7f26f25 100644 --- a/wgpu-hal/src/dx12/descriptor.rs +++ b/wgpu-hal/src/dx12/descriptor.rs @@ -1,16 +1,18 @@ -use super::null_comptr_check; -use crate::auxil::dxgi::result::HResult as _; +use std::fmt; + use bit_set::BitSet; use parking_lot::Mutex; use range_alloc::RangeAllocator; -use std::fmt; +use windows::Win32::Graphics::Direct3D12; + +use crate::auxil::dxgi::result::HResult as _; const HEAP_SIZE_FIXED: usize = 64; #[derive(Copy, Clone)] pub(super) struct DualHandle { - cpu: d3d12::CpuDescriptor, - pub gpu: d3d12::GpuDescriptor, + cpu: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE, + pub gpu: Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE, /// How large the block allocated to this handle is. count: u64, } @@ -28,8 +30,8 @@ impl fmt::Debug for DualHandle { type DescriptorIndex = u64; pub(super) struct GeneralHeap { - pub raw: d3d12::DescriptorHeap, - ty: d3d12::DescriptorHeapType, + pub raw: Direct3D12::ID3D12DescriptorHeap, + ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE, handle_size: u64, total_handles: u64, start: DualHandle, @@ -38,34 +40,34 @@ pub(super) struct GeneralHeap { impl GeneralHeap { pub(super) fn new( - device: d3d12::Device, - ty: d3d12::DescriptorHeapType, + device: &Direct3D12::ID3D12Device, + ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE, total_handles: u64, ) -> Result { let raw = { profiling::scope!("ID3D12Device::CreateDescriptorHeap"); - device - .create_descriptor_heap( - total_handles as u32, - ty, - d3d12::DescriptorHeapFlags::SHADER_VISIBLE, - 0, - ) + let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC { + Type: ty, + NumDescriptors: total_handles as u32, + Flags: Direct3D12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, + NodeMask: 0, + }; + unsafe { device.CreateDescriptorHeap::(&desc) } .into_device_result("Descriptor heap creation")? }; - null_comptr_check(&raw)?; + let start = DualHandle { + cpu: unsafe { raw.GetCPUDescriptorHandleForHeapStart() }, + gpu: unsafe { raw.GetGPUDescriptorHandleForHeapStart() }, + count: 0, + }; Ok(Self { - raw: raw.clone(), + raw, ty, - handle_size: device.get_descriptor_increment_size(ty) as u64, + handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as u64, total_handles, - start: DualHandle { - cpu: raw.start_cpu_descriptor(), - gpu: raw.start_gpu_descriptor(), - count: 0, - }, + start, ranges: Mutex::new(RangeAllocator::new(0..total_handles)), }) } @@ -79,14 +81,14 @@ impl GeneralHeap { } } - fn cpu_descriptor_at(&self, index: u64) -> d3d12::CpuDescriptor { - d3d12::CpuDescriptor { + fn cpu_descriptor_at(&self, index: u64) -> Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE { + Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE { ptr: self.start.cpu.ptr + (self.handle_size * index) as usize, } } - fn gpu_descriptor_at(&self, index: u64) -> d3d12::GpuDescriptor { - d3d12::GpuDescriptor { + fn gpu_descriptor_at(&self, index: u64) -> Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE { + Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE { ptr: self.start.gpu.ptr + self.handle_size * index, } } @@ -109,41 +111,42 @@ impl GeneralHeap { /// Fixed-size free-list allocator for CPU descriptors. struct FixedSizeHeap { - _raw: d3d12::DescriptorHeap, + _raw: Direct3D12::ID3D12DescriptorHeap, /// Bit flag representation of available handles in the heap. /// /// 0 - Occupied /// 1 - free availability: u64, handle_size: usize, - start: d3d12::CpuDescriptor, + start: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE, } impl FixedSizeHeap { fn new( - device: &d3d12::Device, - ty: d3d12::DescriptorHeapType, + device: &Direct3D12::ID3D12Device, + ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE, ) -> Result { - let heap = device - .create_descriptor_heap( - HEAP_SIZE_FIXED as _, - ty, - d3d12::DescriptorHeapFlags::empty(), - 0, - ) - .into_device_result("Descriptor heap creation")?; - - null_comptr_check(&heap)?; + let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC { + Type: ty, + NumDescriptors: HEAP_SIZE_FIXED as u32, + Flags: Direct3D12::D3D12_DESCRIPTOR_HEAP_FLAG_NONE, + NodeMask: 0, + }; + let heap = + unsafe { device.CreateDescriptorHeap::(&desc) } + .into_device_result("Descriptor heap creation")?; Ok(Self { - handle_size: device.get_descriptor_increment_size(ty) as _, + handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as usize, availability: !0, // all free! - start: heap.start_cpu_descriptor(), + start: unsafe { heap.GetCPUDescriptorHandleForHeapStart() }, _raw: heap, }) } - fn alloc_handle(&mut self) -> Result { + fn alloc_handle( + &mut self, + ) -> Result { // Find first free slot. let slot = self.availability.trailing_zeros() as usize; if slot >= HEAP_SIZE_FIXED { @@ -153,12 +156,12 @@ impl FixedSizeHeap { // Set the slot as occupied. self.availability ^= 1 << slot; - Ok(d3d12::CpuDescriptor { + Ok(Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE { ptr: self.start.ptr + self.handle_size * slot, }) } - fn free_handle(&mut self, handle: d3d12::CpuDescriptor) { + fn free_handle(&mut self, handle: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE) { let slot = (handle.ptr - self.start.ptr) / self.handle_size; assert!(slot < HEAP_SIZE_FIXED); assert_eq!(self.availability & (1 << slot), 0); @@ -172,7 +175,7 @@ impl FixedSizeHeap { #[derive(Clone, Copy)] pub(super) struct Handle { - pub raw: d3d12::CpuDescriptor, + pub raw: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE, heap_index: usize, } @@ -186,14 +189,17 @@ impl fmt::Debug for Handle { } pub(super) struct CpuPool { - device: d3d12::Device, - ty: d3d12::DescriptorHeapType, + device: Direct3D12::ID3D12Device, + ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE, heaps: Vec, available_heap_indices: BitSet, } impl CpuPool { - pub(super) fn new(device: d3d12::Device, ty: d3d12::DescriptorHeapType) -> Self { + pub(super) fn new( + device: Direct3D12::ID3D12Device, + ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE, + ) -> Self { Self { device, ty, @@ -234,13 +240,13 @@ impl CpuPool { } pub(super) struct CpuHeapInner { - pub _raw: d3d12::DescriptorHeap, - pub stage: Vec, + pub _raw: Direct3D12::ID3D12DescriptorHeap, + pub stage: Vec, } pub(super) struct CpuHeap { pub inner: Mutex, - start: d3d12::CpuDescriptor, + start: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE, handle_size: u32, total: u32, } @@ -250,30 +256,35 @@ unsafe impl Sync for CpuHeap {} impl CpuHeap { pub(super) fn new( - device: d3d12::Device, - ty: d3d12::DescriptorHeapType, + device: &Direct3D12::ID3D12Device, + ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE, total: u32, ) -> Result { - let handle_size = device.get_descriptor_increment_size(ty); - let raw = device - .create_descriptor_heap(total, ty, d3d12::DescriptorHeapFlags::empty(), 0) + let handle_size = unsafe { device.GetDescriptorHandleIncrementSize(ty) }; + let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC { + Type: ty, + NumDescriptors: total, + Flags: Direct3D12::D3D12_DESCRIPTOR_HEAP_FLAG_NONE, + NodeMask: 0, + }; + let raw = unsafe { device.CreateDescriptorHeap::(&desc) } .into_device_result("CPU descriptor heap creation")?; - null_comptr_check(&raw)?; + let start = unsafe { raw.GetCPUDescriptorHandleForHeapStart() }; Ok(Self { inner: Mutex::new(CpuHeapInner { - _raw: raw.clone(), + _raw: raw, stage: Vec::new(), }), - start: raw.start_cpu_descriptor(), + start, handle_size, total, }) } - pub(super) fn at(&self, index: u32) -> d3d12::CpuDescriptor { - d3d12::CpuDescriptor { + pub(super) fn at(&self, index: u32) -> Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE { + Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE { ptr: self.start.ptr + (self.handle_size * index) as usize, } } @@ -290,7 +301,7 @@ impl fmt::Debug for CpuHeap { } pub(super) unsafe fn upload( - device: d3d12::Device, + device: &Direct3D12::ID3D12Device, src: &CpuHeapInner, dst: &GeneralHeap, dummy_copy_counts: &[u32], @@ -301,11 +312,11 @@ pub(super) unsafe fn upload( device.CopyDescriptors( 1, &dst.cpu_descriptor_at(index), - &count, + Some(&count), count, src.stage.as_ptr(), - dummy_copy_counts.as_ptr(), - dst.ty as u32, + Some(dummy_copy_counts.as_ptr()), + dst.ty, ) }; Ok(dst.at(index, count as u64)) diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index 8cfd8deaee..43425bb5f1 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -1,23 +1,26 @@ -use crate::{ - auxil::{self, dxgi::result::HResult as _}, - dx12::shader_compilation, - DeviceError, -}; -use d3d12::ComPtr; - -use super::{conv, descriptor, null_comptr_check, view}; -use parking_lot::Mutex; use std::{ - ffi, mem, + ffi, + mem::{self, size_of}, num::NonZeroU32, ptr, sync::Arc, time::{Duration, Instant}, }; -use winapi::{ - shared::{dxgiformat, dxgitype, minwindef::BOOL, winerror}, - um::{d3d12 as d3d12_ty, synchapi, winbase}, - Interface, + +use parking_lot::Mutex; +use windows::{ + core::Interface as _, + Win32::{ + Foundation, + Graphics::{Direct3D12, Dxgi}, + System::Threading, + }, +}; + +use super::{conv, descriptor, D3D12Lib}; +use crate::{ + auxil::{self, dxgi::result::HResult}, + dx12::{borrow_optional_interface_temporarily, shader_compilation, Event}, }; // this has to match Naga's HLSL backend, and also needs to be null-terminated @@ -25,156 +28,181 @@ const NAGA_LOCATION_SEMANTIC: &[u8] = b"LOC\0"; impl super::Device { pub(super) fn new( - raw: d3d12::Device, - present_queue: d3d12::CommandQueue, + raw: Direct3D12::ID3D12Device, + present_queue: Direct3D12::ID3D12CommandQueue, limits: &wgt::Limits, memory_hints: &wgt::MemoryHints, private_caps: super::PrivateCapabilities, - library: &Arc, + library: &Arc, dxc_container: Option>, - ) -> Result { - let mem_allocator = if private_caps.suballocation_supported { - super::suballocation::create_allocator_wrapper(&raw, memory_hints)? - } else { - None - }; + ) -> Result { + let mem_allocator = super::suballocation::create_allocator_wrapper(&raw, memory_hints)?; - let mut idle_fence = d3d12::Fence::null(); - let hr = unsafe { + let idle_fence: Direct3D12::ID3D12Fence = unsafe { profiling::scope!("ID3D12Device::CreateFence"); - raw.CreateFence( - 0, - d3d12_ty::D3D12_FENCE_FLAG_NONE, - &d3d12_ty::ID3D12Fence::uuidof(), - idle_fence.mut_void(), - ) + raw.CreateFence(0, Direct3D12::D3D12_FENCE_FLAG_NONE) + } + .into_device_result("Idle fence creation")?; + + let raw_desc = Direct3D12::D3D12_RESOURCE_DESC { + Dimension: Direct3D12::D3D12_RESOURCE_DIMENSION_BUFFER, + Alignment: 0, + Width: super::ZERO_BUFFER_SIZE, + Height: 1, + DepthOrArraySize: 1, + MipLevels: 1, + Format: Dxgi::Common::DXGI_FORMAT_UNKNOWN, + SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + Layout: Direct3D12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + Flags: Direct3D12::D3D12_RESOURCE_FLAG_NONE, }; - hr.into_device_result("Idle fence creation")?; - null_comptr_check(&idle_fence)?; + let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { + Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, + CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, + MemoryPoolPreference: match private_caps.memory_architecture { + super::MemoryArchitecture::Unified { .. } => Direct3D12::D3D12_MEMORY_POOL_L0, + super::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1, + }, + CreationNodeMask: 0, + VisibleNodeMask: 0, + }; - let mut zero_buffer = d3d12::Resource::null(); + profiling::scope!("Zero Buffer Allocation"); + let mut zero_buffer = None::; unsafe { - let raw_desc = d3d12_ty::D3D12_RESOURCE_DESC { - Dimension: d3d12_ty::D3D12_RESOURCE_DIMENSION_BUFFER, - Alignment: 0, - Width: super::ZERO_BUFFER_SIZE, - Height: 1, - DepthOrArraySize: 1, - MipLevels: 1, - Format: dxgiformat::DXGI_FORMAT_UNKNOWN, - SampleDesc: dxgitype::DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - Layout: d3d12_ty::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - Flags: d3d12_ty::D3D12_RESOURCE_FLAG_NONE, - }; - - let heap_properties = d3d12_ty::D3D12_HEAP_PROPERTIES { - Type: d3d12_ty::D3D12_HEAP_TYPE_CUSTOM, - CPUPageProperty: d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, - MemoryPoolPreference: match private_caps.memory_architecture { - super::MemoryArchitecture::Unified { .. } => d3d12_ty::D3D12_MEMORY_POOL_L0, - super::MemoryArchitecture::NonUnified => d3d12_ty::D3D12_MEMORY_POOL_L1, - }, - CreationNodeMask: 0, - VisibleNodeMask: 0, - }; - - profiling::scope!("Zero Buffer Allocation"); raw.CreateCommittedResource( &heap_properties, - d3d12_ty::D3D12_HEAP_FLAG_NONE, + Direct3D12::D3D12_HEAP_FLAG_NONE, &raw_desc, - d3d12_ty::D3D12_RESOURCE_STATE_COMMON, - ptr::null(), - &d3d12_ty::ID3D12Resource::uuidof(), - zero_buffer.mut_void(), + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, + &mut zero_buffer, ) - .into_device_result("Zero buffer creation")?; + } + .into_device_result("Zero buffer creation")?; - null_comptr_check(&zero_buffer)?; + let zero_buffer = zero_buffer.ok_or(crate::DeviceError::Unexpected)?; - // Note: without `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED` - // this resource is zeroed by default. - }; + // Note: without `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED` + // this resource is zeroed by default. // maximum number of CBV/SRV/UAV descriptors in heap for Tier 1 let capacity_views = limits.max_non_sampler_bindings as u64; let capacity_samplers = 2_048; + fn create_command_signature( + raw: &Direct3D12::ID3D12Device, + byte_stride: usize, + arguments: &[Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC], + node_mask: u32, + ) -> Result { + let mut signature = None; + unsafe { + raw.CreateCommandSignature( + &Direct3D12::D3D12_COMMAND_SIGNATURE_DESC { + ByteStride: byte_stride as u32, + NumArgumentDescs: arguments.len() as u32, + pArgumentDescs: arguments.as_ptr(), + NodeMask: node_mask, + }, + None, + &mut signature, + ) + } + .into_device_result("Command signature creation")?; + signature.ok_or(crate::DeviceError::Unexpected) + } + let shared = super::DeviceShared { zero_buffer, cmd_signatures: super::CommandSignatures { - draw: raw - .create_command_signature( - d3d12::RootSignature::null(), - &[d3d12::IndirectArgument::draw()], - mem::size_of::() as u32, - 0, - ) - .into_device_result("Command (draw) signature creation")?, - draw_indexed: raw - .create_command_signature( - d3d12::RootSignature::null(), - &[d3d12::IndirectArgument::draw_indexed()], - mem::size_of::() as u32, - 0, - ) - .into_device_result("Command (draw_indexed) signature creation")?, - dispatch: raw - .create_command_signature( - d3d12::RootSignature::null(), - &[d3d12::IndirectArgument::dispatch()], - mem::size_of::() as u32, - 0, - ) - .into_device_result("Command (dispatch) signature creation")?, + draw: create_command_signature( + &raw, + size_of::(), + &[Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC { + Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, + ..Default::default() + }], + 0, + )?, + draw_indexed: create_command_signature( + &raw, + size_of::(), + &[Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC { + Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED, + ..Default::default() + }], + 0, + )?, + dispatch: create_command_signature( + &raw, + size_of::(), + &[Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC { + Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH, + ..Default::default() + }], + 0, + )?, }, heap_views: descriptor::GeneralHeap::new( - raw.clone(), - d3d12::DescriptorHeapType::CbvSrvUav, + &raw, + Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, capacity_views, )?, heap_samplers: descriptor::GeneralHeap::new( - raw.clone(), - d3d12::DescriptorHeapType::Sampler, + &raw, + Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, capacity_samplers, )?, }; - let mut rtv_pool = descriptor::CpuPool::new(raw.clone(), d3d12::DescriptorHeapType::Rtv); + let mut rtv_pool = + descriptor::CpuPool::new(raw.clone(), Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_RTV); let null_rtv_handle = rtv_pool.alloc_handle()?; // A null pResource is used to initialize a null descriptor, // which guarantees D3D11-like null binding behavior (reading 0s, writes are discarded) - raw.create_render_target_view( - ComPtr::null(), - &d3d12::RenderTargetViewDesc::texture_2d(dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM, 0, 0), - null_rtv_handle.raw, - ); + unsafe { + raw.CreateRenderTargetView( + None, + Some(&Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC { + Format: Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM, + ViewDimension: Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2D, + Anonymous: Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC_0 { + Texture2D: Direct3D12::D3D12_TEX2D_RTV { + MipSlice: 0, + PlaneSlice: 0, + }, + }, + }), + null_rtv_handle.raw, + ) + }; Ok(super::Device { raw: raw.clone(), present_queue, idler: super::Idler { fence: idle_fence, - event: d3d12::Event::create(false, false), + event: Event::create(false, false)?, }, private_caps, shared: Arc::new(shared), rtv_pool: Mutex::new(rtv_pool), dsv_pool: Mutex::new(descriptor::CpuPool::new( raw.clone(), - d3d12::DescriptorHeapType::Dsv, + Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_DSV, )), srv_uav_pool: Mutex::new(descriptor::CpuPool::new( raw.clone(), - d3d12::DescriptorHeapType::CbvSrvUav, + Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, )), sampler_pool: Mutex::new(descriptor::CpuPool::new( raw, - d3d12::DescriptorHeapType::Sampler, + Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, )), library: Arc::clone(library), #[cfg(feature = "renderdoc")] @@ -189,20 +217,22 @@ impl super::Device { // Blocks until the dedicated present queue is finished with all of its work. // // Once this method completes, the surface is able to be resized or deleted. - pub(super) unsafe fn wait_for_present_queue_idle(&self) -> Result<(), DeviceError> { - let cur_value = self.idler.fence.get_value(); + pub(super) unsafe fn wait_for_present_queue_idle(&self) -> Result<(), crate::DeviceError> { + let cur_value = unsafe { self.idler.fence.GetCompletedValue() }; if cur_value == !0 { - return Err(DeviceError::Lost); + return Err(crate::DeviceError::Lost); } let value = cur_value + 1; - self.present_queue.signal(&self.idler.fence, value); - let hr = self - .idler - .fence - .set_event_on_completion(self.idler.event, value); + unsafe { self.present_queue.Signal(&self.idler.fence, value) } + .into_device_result("Signal")?; + let hr = unsafe { + self.idler + .fence + .SetEventOnCompletion(value, self.idler.event.0) + }; hr.into_device_result("Set event")?; - unsafe { synchapi::WaitForSingleObject(self.idler.event.0, winbase::INFINITE) }; + unsafe { Threading::WaitForSingleObject(self.idler.event.0, Threading::INFINITE) }; Ok(()) } @@ -258,7 +288,7 @@ impl super::Device { }; let full_stage = format!( - "{}_{}\0", + "{}_{}", naga_stage.to_hlsl_str(), naga_options.shader_model.to_str() ); @@ -276,28 +306,33 @@ impl super::Device { let source_name = stage.module.raw_name.as_deref(); // Compile with DXC if available, otherwise fall back to FXC - let (result, log_level) = if let Some(ref dxc_container) = self.dxc_container { + let result = if let Some(ref dxc_container) = self.dxc_container { shader_compilation::compile_dxc( self, &source, source_name, raw_ep, stage_bit, - full_stage, + &full_stage, dxc_container, ) } else { - let full_stage = ffi::CStr::from_bytes_with_nul(full_stage.as_bytes()).unwrap(); shader_compilation::compile_fxc( self, &source, source_name, - &ffi::CString::new(raw_ep.as_str()).unwrap(), + raw_ep, stage_bit, - full_stage, + &full_stage, ) }; + let log_level = if result.is_ok() { + log::Level::Info + } else { + log::Level::Error + }; + log::log!( log_level, "Naga generated shader for {:?} at {:?}:\n{}", @@ -308,16 +343,16 @@ impl super::Device { result } - pub fn raw_device(&self) -> &d3d12::Device { + pub fn raw_device(&self) -> &Direct3D12::ID3D12Device { &self.raw } - pub fn raw_queue(&self) -> &d3d12::CommandQueue { + pub fn raw_queue(&self) -> &Direct3D12::ID3D12CommandQueue { &self.present_queue } pub unsafe fn texture_from_raw( - resource: d3d12::Resource, + resource: Direct3D12::ID3D12Resource, format: wgt::TextureFormat, dimension: wgt::TextureDimension, size: wgt::Extent3d, @@ -336,7 +371,7 @@ impl super::Device { } pub unsafe fn buffer_from_raw( - resource: d3d12::Resource, + resource: Direct3D12::ID3D12Resource, size: wgt::BufferAddress, ) -> super::Buffer { super::Buffer { @@ -350,45 +385,42 @@ impl super::Device { impl crate::Device for super::Device { type A = super::Api; - unsafe fn exit(mut self, _queue: super::Queue) { + unsafe fn exit(self, _queue: super::Queue) { self.rtv_pool.lock().free_handle(self.null_rtv_handle); - self.mem_allocator = None; } unsafe fn create_buffer( &self, desc: &crate::BufferDescriptor, - ) -> Result { - let mut resource = d3d12::Resource::null(); + ) -> Result { let mut size = desc.size; if desc.usage.contains(crate::BufferUses::UNIFORM) { - let align_mask = d3d12_ty::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT as u64 - 1; + let align_mask = Direct3D12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT as u64 - 1; size = ((size - 1) | align_mask) + 1; } - let raw_desc = d3d12_ty::D3D12_RESOURCE_DESC { - Dimension: d3d12_ty::D3D12_RESOURCE_DIMENSION_BUFFER, + let raw_desc = Direct3D12::D3D12_RESOURCE_DESC { + Dimension: Direct3D12::D3D12_RESOURCE_DIMENSION_BUFFER, Alignment: 0, Width: size, Height: 1, DepthOrArraySize: 1, MipLevels: 1, - Format: dxgiformat::DXGI_FORMAT_UNKNOWN, - SampleDesc: dxgitype::DXGI_SAMPLE_DESC { + Format: Dxgi::Common::DXGI_FORMAT_UNKNOWN, + SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { Count: 1, Quality: 0, }, - Layout: d3d12_ty::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + Layout: Direct3D12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, Flags: conv::map_buffer_usage_to_resource_flags(desc.usage), }; - let (hr, allocation) = - super::suballocation::create_buffer_resource(self, desc, raw_desc, &mut resource)?; + let (resource, allocation) = + super::suballocation::create_buffer_resource(self, desc, raw_desc)?; - hr.into_device_result("Buffer creation")?; if let Some(label) = desc.label { - let cwstr = conv::map_label(label); - unsafe { resource.SetName(cwstr.as_ptr()) }; + unsafe { resource.SetName(&windows::core::HSTRING::from(label)) } + .into_device_result("SetName")?; } self.counters.buffers.add(1); @@ -401,31 +433,29 @@ impl crate::Device for super::Device { } unsafe fn destroy_buffer(&self, mut buffer: super::Buffer) { - // Only happens when it's using the windows_rs feature and there's an allocation + // Always Some except on Intel Xe: https://github.com/gfx-rs/wgpu/issues/3552 if let Some(alloc) = buffer.allocation.take() { // Resource should be dropped before free suballocation drop(buffer); - super::suballocation::free_buffer_allocation( - self, - alloc, - // SAFETY: for allocations to exist, the allocator must exist - unsafe { self.mem_allocator.as_ref().unwrap_unchecked() }, - ); + super::suballocation::free_buffer_allocation(self, alloc, &self.mem_allocator); } self.counters.buffers.sub(1); } + unsafe fn add_raw_buffer(&self, _buffer: &super::Buffer) { + self.counters.buffers.add(1); + } + unsafe fn map_buffer( &self, buffer: &super::Buffer, range: crate::MemoryRange, - ) -> Result { + ) -> Result { let mut ptr = ptr::null_mut(); // TODO: 0 for subresource should be fine here until map and unmap buffer is subresource aware? - let hr = unsafe { (*buffer.resource).Map(0, ptr::null(), &mut ptr) }; - hr.into_device_result("Map buffer")?; + unsafe { buffer.resource.Map(0, None, Some(&mut ptr)) }.into_device_result("Map buffer")?; Ok(crate::BufferMapping { ptr: ptr::NonNull::new(unsafe { ptr.offset(range.start as isize).cast::() }) @@ -437,7 +467,7 @@ impl crate::Device for super::Device { } unsafe fn unmap_buffer(&self, buffer: &super::Buffer) { - unsafe { (*buffer.resource).Unmap(0, ptr::null()) }; + unsafe { buffer.resource.Unmap(0, None) }; } unsafe fn flush_mapped_ranges(&self, _buffer: &super::Buffer, _ranges: I) {} @@ -446,12 +476,8 @@ impl crate::Device for super::Device { unsafe fn create_texture( &self, desc: &crate::TextureDescriptor, - ) -> Result { - use super::suballocation::create_texture_resource; - - let mut resource = d3d12::Resource::null(); - - let raw_desc = d3d12_ty::D3D12_RESOURCE_DESC { + ) -> Result { + let raw_desc = Direct3D12::D3D12_RESOURCE_DESC { Dimension: conv::map_texture_dimension(desc.dimension), Alignment: 0, Width: desc.size.width as u64, @@ -464,20 +490,20 @@ impl crate::Device for super::Device { !desc.view_formats.is_empty(), self.private_caps.casting_fully_typed_format_supported, ), - SampleDesc: dxgitype::DXGI_SAMPLE_DESC { + SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { Count: desc.sample_count, Quality: 0, }, - Layout: d3d12_ty::D3D12_TEXTURE_LAYOUT_UNKNOWN, + Layout: Direct3D12::D3D12_TEXTURE_LAYOUT_UNKNOWN, Flags: conv::map_texture_usage_to_resource_flags(desc.usage), }; - let (hr, allocation) = create_texture_resource(self, desc, raw_desc, &mut resource)?; + let (resource, allocation) = + super::suballocation::create_texture_resource(self, desc, raw_desc)?; - hr.into_device_result("Texture creation")?; if let Some(label) = desc.label { - let cwstr = conv::map_label(label); - unsafe { resource.SetName(cwstr.as_ptr()) }; + unsafe { resource.SetName(&windows::core::HSTRING::from(label)) } + .into_device_result("SetName")?; } self.counters.textures.add(1); @@ -502,18 +528,22 @@ impl crate::Device for super::Device { self, alloc, // SAFETY: for allocations to exist, the allocator must exist - unsafe { self.mem_allocator.as_ref().unwrap_unchecked() }, + &self.mem_allocator, ); } self.counters.textures.sub(1); } + unsafe fn add_raw_texture(&self, _texture: &super::Texture) { + self.counters.textures.add(1); + } + unsafe fn create_texture_view( &self, texture: &super::Texture, desc: &crate::TextureViewDescriptor, - ) -> Result { + ) -> Result { let view_desc = desc.to_internal(texture); self.counters.texture_views.add(1); @@ -531,8 +561,8 @@ impl crate::Device for super::Device { let handle = self.srv_uav_pool.lock().alloc_handle()?; unsafe { self.raw.CreateShaderResourceView( - texture.resource.as_mut_ptr(), - &raw_desc, + &texture.resource, + Some(&raw_desc), handle.raw, ) }; @@ -551,9 +581,9 @@ impl crate::Device for super::Device { let handle = self.srv_uav_pool.lock().alloc_handle()?; unsafe { self.raw.CreateUnorderedAccessView( - texture.resource.as_mut_ptr(), - ptr::null_mut(), - &raw_desc, + &texture.resource, + None, + Some(&raw_desc), handle.raw, ); } @@ -568,11 +598,8 @@ impl crate::Device for super::Device { let raw_desc = unsafe { view_desc.to_rtv() }; let handle = self.rtv_pool.lock().alloc_handle()?; unsafe { - self.raw.CreateRenderTargetView( - texture.resource.as_mut_ptr(), - &raw_desc, - handle.raw, - ) + self.raw + .CreateRenderTargetView(&texture.resource, Some(&raw_desc), handle.raw) }; Some(handle) } else { @@ -585,11 +612,8 @@ impl crate::Device for super::Device { let raw_desc = unsafe { view_desc.to_dsv(true) }; let handle = self.dsv_pool.lock().alloc_handle()?; unsafe { - self.raw.CreateDepthStencilView( - texture.resource.as_mut_ptr(), - &raw_desc, - handle.raw, - ) + self.raw + .CreateDepthStencilView(&texture.resource, Some(&raw_desc), handle.raw) }; Some(handle) } else { @@ -602,11 +626,8 @@ impl crate::Device for super::Device { let raw_desc = unsafe { view_desc.to_dsv(false) }; let handle = self.dsv_pool.lock().alloc_handle()?; unsafe { - self.raw.CreateDepthStencilView( - texture.resource.as_mut_ptr(), - &raw_desc, - handle.raw, - ) + self.raw + .CreateDepthStencilView(&texture.resource, Some(&raw_desc), handle.raw) }; Some(handle) } else { @@ -644,38 +665,46 @@ impl crate::Device for super::Device { unsafe fn create_sampler( &self, desc: &crate::SamplerDescriptor, - ) -> Result { + ) -> Result { let handle = self.sampler_pool.lock().alloc_handle()?; let reduction = match desc.compare { - Some(_) => d3d12_ty::D3D12_FILTER_REDUCTION_TYPE_COMPARISON, - None => d3d12_ty::D3D12_FILTER_REDUCTION_TYPE_STANDARD, + Some(_) => Direct3D12::D3D12_FILTER_REDUCTION_TYPE_COMPARISON, + None => Direct3D12::D3D12_FILTER_REDUCTION_TYPE_STANDARD, }; - let mut filter = conv::map_filter_mode(desc.min_filter) << d3d12_ty::D3D12_MIN_FILTER_SHIFT - | conv::map_filter_mode(desc.mag_filter) << d3d12_ty::D3D12_MAG_FILTER_SHIFT - | conv::map_filter_mode(desc.mipmap_filter) << d3d12_ty::D3D12_MIP_FILTER_SHIFT - | reduction << d3d12_ty::D3D12_FILTER_REDUCTION_TYPE_SHIFT; + let mut filter = Direct3D12::D3D12_FILTER( + conv::map_filter_mode(desc.min_filter).0 << Direct3D12::D3D12_MIN_FILTER_SHIFT + | conv::map_filter_mode(desc.mag_filter).0 << Direct3D12::D3D12_MAG_FILTER_SHIFT + | conv::map_filter_mode(desc.mipmap_filter).0 << Direct3D12::D3D12_MIP_FILTER_SHIFT + | reduction.0 << Direct3D12::D3D12_FILTER_REDUCTION_TYPE_SHIFT, + ); if desc.anisotropy_clamp != 1 { - filter |= d3d12_ty::D3D12_FILTER_ANISOTROPIC; + filter.0 |= Direct3D12::D3D12_FILTER_ANISOTROPIC.0; }; let border_color = conv::map_border_color(desc.border_color); - self.raw.create_sampler( - handle.raw, - filter, - [ - conv::map_address_mode(desc.address_modes[0]), - conv::map_address_mode(desc.address_modes[1]), - conv::map_address_mode(desc.address_modes[2]), - ], - 0.0, - desc.anisotropy_clamp as u32, - conv::map_comparison(desc.compare.unwrap_or(wgt::CompareFunction::Always)), - border_color, - desc.lod_clamp.clone(), - ); + unsafe { + self.raw.CreateSampler( + &Direct3D12::D3D12_SAMPLER_DESC { + Filter: filter, + AddressU: conv::map_address_mode(desc.address_modes[0]), + AddressV: conv::map_address_mode(desc.address_modes[1]), + AddressW: conv::map_address_mode(desc.address_modes[2]), + MipLODBias: 0f32, + MaxAnisotropy: desc.anisotropy_clamp as u32, + + ComparisonFunc: conv::map_comparison( + desc.compare.unwrap_or(wgt::CompareFunction::Always), + ), + BorderColor: border_color, + MinLOD: desc.lod_clamp.start, + MaxLOD: desc.lod_clamp.end, + }, + handle.raw, + ) + }; self.counters.samplers.add(1); @@ -690,15 +719,16 @@ impl crate::Device for super::Device { unsafe fn create_command_encoder( &self, desc: &crate::CommandEncoderDescriptor, - ) -> Result { - let allocator = self - .raw - .create_command_allocator(d3d12::CmdListType::Direct) - .into_device_result("Command allocator creation")?; + ) -> Result { + let allocator: Direct3D12::ID3D12CommandAllocator = unsafe { + self.raw + .CreateCommandAllocator(Direct3D12::D3D12_COMMAND_LIST_TYPE_DIRECT) + } + .into_device_result("Command allocator creation")?; if let Some(label) = desc.label { - let cwstr = conv::map_label(label); - unsafe { allocator.SetName(cwstr.as_ptr()) }; + unsafe { allocator.SetName(&windows::core::HSTRING::from(label)) } + .into_device_result("SetName")?; } self.counters.command_encoders.add(1); @@ -723,7 +753,7 @@ impl crate::Device for super::Device { unsafe fn create_bind_group_layout( &self, desc: &crate::BindGroupLayoutDescriptor, - ) -> Result { + ) -> Result { let (mut num_buffer_views, mut num_samplers, mut num_texture_views) = (0, 0, 0); for entry in desc.entries.iter() { let count = entry.count.map_or(1, NonZeroU32::get); @@ -748,8 +778,8 @@ impl crate::Device for super::Device { entries: desc.entries.to_vec(), cpu_heap_views: if num_views != 0 { let heap = descriptor::CpuHeap::new( - self.raw.clone(), - d3d12::DescriptorHeapType::CbvSrvUav, + &self.raw, + Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, num_views, )?; Some(heap) @@ -758,8 +788,8 @@ impl crate::Device for super::Device { }, cpu_heap_samplers: if num_samplers != 0 { let heap = descriptor::CpuHeap::new( - self.raw.clone(), - d3d12::DescriptorHeapType::Sampler, + &self.raw, + Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_samplers, )?; Some(heap) @@ -777,7 +807,7 @@ impl crate::Device for super::Device { unsafe fn create_pipeline_layout( &self, desc: &crate::PipelineLayoutDescriptor, - ) -> Result { + ) -> Result { use naga::back::hlsl; // Pipeline layouts are implemented as RootSignature for D3D12. // @@ -809,13 +839,6 @@ impl crate::Device for super::Device { // Currently impossible because wgpu-core only re-binds the descriptor sets based // on Vulkan-like layout compatibility rules. - fn native_binding(bt: &hlsl::BindTarget) -> d3d12::Binding { - d3d12::Binding { - space: bt.space as u32, - register: bt.register, - } - } - let mut binding_map = hlsl::BindingMap::default(); let (mut bind_cbv, mut bind_srv, mut bind_uav, mut bind_sampler) = ( hlsl::BindTarget::default(), @@ -838,11 +861,17 @@ impl crate::Device for super::Device { if pc_start != u32::MAX && pc_end != u32::MIN { let parameter_index = parameters.len(); let size = (pc_end - pc_start) / 4; - parameters.push(d3d12::RootParameter::constants( - d3d12::ShaderVisibility::All, - native_binding(&bind_cbv), - size, - )); + parameters.push(Direct3D12::D3D12_ROOT_PARAMETER { + ParameterType: Direct3D12::D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, + Anonymous: Direct3D12::D3D12_ROOT_PARAMETER_0 { + Constants: Direct3D12::D3D12_ROOT_CONSTANTS { + ShaderRegister: bind_cbv.register, + RegisterSpace: bind_cbv.space as u32, + Num32BitValues: size, + }, + }, + ShaderVisibility: Direct3D12::D3D12_SHADER_VISIBILITY_ALL, + }); let binding = bind_cbv.clone(); bind_cbv.register += 1; root_constant_info = Some(super::RootConstantInfo { @@ -906,10 +935,11 @@ impl crate::Device for super::Device { ref other => conv::map_binding_type(other), }; let bt = match range_ty { - d3d12::DescriptorRangeType::CBV => &mut bind_cbv, - d3d12::DescriptorRangeType::SRV => &mut bind_srv, - d3d12::DescriptorRangeType::UAV => &mut bind_uav, - d3d12::DescriptorRangeType::Sampler => continue, + Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV => &mut bind_cbv, + Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV => &mut bind_srv, + Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV => &mut bind_uav, + Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER => continue, + _ => todo!(), }; binding_map.insert( @@ -922,19 +952,28 @@ impl crate::Device for super::Device { ..bt.clone() }, ); - ranges.push(d3d12::DescriptorRange::new( - range_ty, - entry.count.map_or(1, |count| count.get()), - native_binding(bt), - d3d12_ty::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND, - )); + ranges.push(Direct3D12::D3D12_DESCRIPTOR_RANGE { + RangeType: range_ty, + NumDescriptors: entry.count.map_or(1, |count| count.get()), + BaseShaderRegister: bt.register, + RegisterSpace: bt.space as u32, + OffsetInDescriptorsFromTableStart: + Direct3D12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND, + }); bt.register += entry.count.map(NonZeroU32::get).unwrap_or(1); } if ranges.len() > range_base { - parameters.push(d3d12::RootParameter::descriptor_table( - conv::map_visibility(visibility_view_static), - &ranges[range_base..], - )); + let range = &ranges[range_base..]; + parameters.push(Direct3D12::D3D12_ROOT_PARAMETER { + ParameterType: Direct3D12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, + Anonymous: Direct3D12::D3D12_ROOT_PARAMETER_0 { + DescriptorTable: Direct3D12::D3D12_ROOT_DESCRIPTOR_TABLE { + NumDescriptorRanges: range.len() as u32, + pDescriptorRanges: range.as_ptr(), + }, + }, + ShaderVisibility: conv::map_visibility(visibility_view_static), + }); info.tables |= super::TableTypes::SRV_CBV_UAV; } @@ -942,7 +981,9 @@ impl crate::Device for super::Device { range_base = ranges.len(); for entry in bgl.entries.iter() { let range_ty = match entry.ty { - wgt::BindingType::Sampler { .. } => d3d12::DescriptorRangeType::Sampler, + wgt::BindingType::Sampler { .. } => { + Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + } _ => continue, }; binding_map.insert( @@ -955,19 +996,28 @@ impl crate::Device for super::Device { ..bind_sampler.clone() }, ); - ranges.push(d3d12::DescriptorRange::new( - range_ty, - entry.count.map_or(1, |count| count.get()), - native_binding(&bind_sampler), - d3d12_ty::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND, - )); + ranges.push(Direct3D12::D3D12_DESCRIPTOR_RANGE { + RangeType: range_ty, + NumDescriptors: entry.count.map_or(1, |count| count.get()), + BaseShaderRegister: bind_sampler.register, + RegisterSpace: bind_sampler.space as u32, + OffsetInDescriptorsFromTableStart: + Direct3D12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND, + }); bind_sampler.register += entry.count.map(NonZeroU32::get).unwrap_or(1); } if ranges.len() > range_base { - parameters.push(d3d12::RootParameter::descriptor_table( - conv::map_visibility(visibility_sampler), - &ranges[range_base..], - )); + let range = &ranges[range_base..]; + parameters.push(Direct3D12::D3D12_ROOT_PARAMETER { + ParameterType: Direct3D12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, + Anonymous: Direct3D12::D3D12_ROOT_PARAMETER_0 { + DescriptorTable: Direct3D12::D3D12_ROOT_DESCRIPTOR_TABLE { + NumDescriptorRanges: range.len() as u32, + pDescriptorRanges: range.as_ptr(), + }, + }, + ShaderVisibility: conv::map_visibility(visibility_sampler), + }); info.tables |= super::TableTypes::SAMPLERS; } @@ -986,17 +1036,17 @@ impl crate::Device for super::Device { let (kind, parameter_ty, bt) = match buffer_ty { wgt::BufferBindingType::Uniform => ( super::BufferViewKind::Constant, - d3d12_ty::D3D12_ROOT_PARAMETER_TYPE_CBV, + Direct3D12::D3D12_ROOT_PARAMETER_TYPE_CBV, &mut bind_cbv, ), wgt::BufferBindingType::Storage { read_only: true } => ( super::BufferViewKind::ShaderResource, - d3d12_ty::D3D12_ROOT_PARAMETER_TYPE_SRV, + Direct3D12::D3D12_ROOT_PARAMETER_TYPE_SRV, &mut bind_srv, ), wgt::BufferBindingType::Storage { read_only: false } => ( super::BufferViewKind::UnorderedAccess, - d3d12_ty::D3D12_ROOT_PARAMETER_TYPE_UAV, + Direct3D12::D3D12_ROOT_PARAMETER_TYPE_UAV, &mut bind_uav, ), }; @@ -1013,11 +1063,16 @@ impl crate::Device for super::Device { ); info.dynamic_buffers.push(kind); - parameters.push(d3d12::RootParameter::descriptor( - parameter_ty, - dynamic_buffers_visibility, - native_binding(bt), - )); + parameters.push(Direct3D12::D3D12_ROOT_PARAMETER { + ParameterType: parameter_ty, + Anonymous: Direct3D12::D3D12_ROOT_PARAMETER_0 { + Descriptor: Direct3D12::D3D12_ROOT_DESCRIPTOR { + ShaderRegister: bt.register, + RegisterSpace: bt.space as u32, + }, + }, + ShaderVisibility: dynamic_buffers_visibility, + }); bt.register += entry.count.map_or(1, NonZeroU32::get); } @@ -1033,11 +1088,17 @@ impl crate::Device for super::Device { | crate::PipelineLayoutFlags::NUM_WORK_GROUPS, ) { let parameter_index = parameters.len(); - parameters.push(d3d12::RootParameter::constants( - d3d12::ShaderVisibility::All, // really needed for VS and CS only - native_binding(&bind_cbv), - 3, // 0 = first_vertex, 1 = first_instance, 2 = other - )); + parameters.push(Direct3D12::D3D12_ROOT_PARAMETER { + ParameterType: Direct3D12::D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, + Anonymous: Direct3D12::D3D12_ROOT_PARAMETER_0 { + Constants: Direct3D12::D3D12_ROOT_CONSTANTS { + ShaderRegister: bind_cbv.register, + RegisterSpace: bind_cbv.space as u32, + Num32BitValues: 3, // 0 = first_vertex, 1 = first_instance, 2 = other + }, + }, + ShaderVisibility: Direct3D12::D3D12_SHADER_VISIBILITY_ALL, // really needed for VS and CS only, + }); let binding = bind_cbv.clone(); bind_cbv.register += 1; (Some(parameter_index as u32), Some(binding)) @@ -1045,43 +1106,29 @@ impl crate::Device for super::Device { (None, None) }; - let (blob, error) = self - .library - .serialize_root_signature( - d3d12::RootSignatureVersion::V1_0, - ¶meters, - &[], - d3d12::RootSignatureFlags::ALLOW_IA_INPUT_LAYOUT, - ) - .map_err(|e| { - log::error!("Unable to find serialization function: {:?}", e); - DeviceError::Lost - })? - .into_device_result("Root signature serialization")?; - - if !error.is_null() { - log::error!( - "Root signature serialization error: {:?}", - unsafe { error.as_c_str() }.to_str().unwrap() - ); - return Err(DeviceError::Lost); - } + let blob = self.library.serialize_root_signature( + Direct3D12::D3D_ROOT_SIGNATURE_VERSION_1_0, + ¶meters, + &[], + Direct3D12::D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, + )?; - let raw = self - .raw - .create_root_signature(blob, 0) - .into_device_result("Root signature creation")?; + let raw = unsafe { + self.raw + .CreateRootSignature::(0, blob.as_slice()) + } + .into_device_result("Root signature creation")?; if let Some(label) = desc.label { - let cwstr = conv::map_label(label); - unsafe { raw.SetName(cwstr.as_ptr()) }; + unsafe { raw.SetName(&windows::core::HSTRING::from(label)) } + .into_device_result("SetName")?; } self.counters.pipeline_layouts.add(1); Ok(super::PipelineLayout { shared: super::PipelineLayoutShared { - signature: raw, + signature: Some(raw), total_root_elements: parameters.len() as super::RootIndex, special_constants_root_index, root_constant_info, @@ -1111,7 +1158,7 @@ impl crate::Device for super::Device { super::TextureView, super::AccelerationStructure, >, - ) -> Result { + ) -> Result { let mut cpu_views = desc .layout .cpu_heap_views @@ -1148,7 +1195,9 @@ impl crate::Device for super::Device { let start = entry.resource_index as usize; let end = start + entry.count as usize; for data in &desc.buffers[start..end] { - dynamic_buffers.push(data.resolve_address()); + dynamic_buffers.push(Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE { + ptr: data.resolve_address(), + }); } } wgt::BindingType::Buffer { ty, .. } => { @@ -1163,57 +1212,57 @@ impl crate::Device for super::Device { match ty { wgt::BufferBindingType::Uniform => { let size_mask = - d3d12_ty::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1; - let raw_desc = d3d12_ty::D3D12_CONSTANT_BUFFER_VIEW_DESC { + Direct3D12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1; + let raw_desc = Direct3D12::D3D12_CONSTANT_BUFFER_VIEW_DESC { BufferLocation: gpu_address, SizeInBytes: ((size - 1) | size_mask) + 1, }; - unsafe { self.raw.CreateConstantBufferView(&raw_desc, handle) }; + unsafe { + self.raw.CreateConstantBufferView(Some(&raw_desc), handle) + }; } wgt::BufferBindingType::Storage { read_only: true } => { - let mut raw_desc = d3d12_ty::D3D12_SHADER_RESOURCE_VIEW_DESC { - Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS, + let raw_desc = Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC { + Format: Dxgi::Common::DXGI_FORMAT_R32_TYPELESS, Shader4ComponentMapping: - view::D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, - ViewDimension: d3d12_ty::D3D12_SRV_DIMENSION_BUFFER, - u: unsafe { mem::zeroed() }, - }; - unsafe { - *raw_desc.u.Buffer_mut() = d3d12_ty::D3D12_BUFFER_SRV { - FirstElement: data.offset / 4, - NumElements: size / 4, - StructureByteStride: 0, - Flags: d3d12_ty::D3D12_BUFFER_SRV_FLAG_RAW, - } + Direct3D12::D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, + ViewDimension: Direct3D12::D3D12_SRV_DIMENSION_BUFFER, + Anonymous: Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC_0 { + Buffer: Direct3D12::D3D12_BUFFER_SRV { + FirstElement: data.offset / 4, + NumElements: size / 4, + StructureByteStride: 0, + Flags: Direct3D12::D3D12_BUFFER_SRV_FLAG_RAW, + }, + }, }; unsafe { self.raw.CreateShaderResourceView( - data.buffer.resource.as_mut_ptr(), - &raw_desc, + &data.buffer.resource, + Some(&raw_desc), handle, ) }; } wgt::BufferBindingType::Storage { read_only: false } => { - let mut raw_desc = d3d12_ty::D3D12_UNORDERED_ACCESS_VIEW_DESC { - Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS, - ViewDimension: d3d12_ty::D3D12_UAV_DIMENSION_BUFFER, - u: unsafe { mem::zeroed() }, - }; - unsafe { - *raw_desc.u.Buffer_mut() = d3d12_ty::D3D12_BUFFER_UAV { - FirstElement: data.offset / 4, - NumElements: size / 4, - StructureByteStride: 0, - CounterOffsetInBytes: 0, - Flags: d3d12_ty::D3D12_BUFFER_UAV_FLAG_RAW, - } + let raw_desc = Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC { + Format: Dxgi::Common::DXGI_FORMAT_R32_TYPELESS, + ViewDimension: Direct3D12::D3D12_UAV_DIMENSION_BUFFER, + Anonymous: Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC_0 { + Buffer: Direct3D12::D3D12_BUFFER_UAV { + FirstElement: data.offset / 4, + NumElements: size / 4, + StructureByteStride: 0, + CounterOffsetInBytes: 0, + Flags: Direct3D12::D3D12_BUFFER_UAV_FLAG_RAW, + }, + }, }; unsafe { self.raw.CreateUnorderedAccessView( - data.buffer.resource.as_mut_ptr(), - ptr::null_mut(), - &raw_desc, + &data.buffer.resource, + None, + Some(&raw_desc), handle, ) }; @@ -1253,7 +1302,7 @@ impl crate::Device for super::Device { Some(inner) => { let dual = unsafe { descriptor::upload( - self.raw.clone(), + &self.raw, &inner, &self.shared.heap_views, &desc.layout.copy_counts, @@ -1267,7 +1316,7 @@ impl crate::Device for super::Device { Some(inner) => { let dual = unsafe { descriptor::upload( - self.raw.clone(), + &self.raw, &inner, &self.shared.heap_samplers, &desc.layout.copy_counts, @@ -1353,15 +1402,15 @@ impl crate::Device for super::Device { *stride = NonZeroU32::new(vbuf.array_stride as u32); let (slot_class, step_rate) = match vbuf.step_mode { wgt::VertexStepMode::Vertex => { - (d3d12_ty::D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0) + (Direct3D12::D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0) } wgt::VertexStepMode::Instance => { - (d3d12_ty::D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1) + (Direct3D12::D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1) } }; for attribute in vbuf.attributes { - input_element_descs.push(d3d12_ty::D3D12_INPUT_ELEMENT_DESC { - SemanticName: NAGA_LOCATION_SEMANTIC.as_ptr().cast(), + input_element_descs.push(Direct3D12::D3D12_INPUT_ELEMENT_DESC { + SemanticName: windows::core::PCSTR(NAGA_LOCATION_SEMANTIC.as_ptr()), SemanticIndex: attribute.shader_location, Format: auxil::dxgi::conv::map_vertex_format(attribute.format), InputSlot: i as u32, @@ -1372,8 +1421,8 @@ impl crate::Device for super::Device { } } - let mut rtv_formats = [dxgiformat::DXGI_FORMAT_UNKNOWN; - d3d12_ty::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize]; + let mut rtv_formats = [Dxgi::Common::DXGI_FORMAT_UNKNOWN; + Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize]; for (rtv_format, ct) in rtv_formats.iter_mut().zip(desc.color_targets) { if let Some(ct) = ct.as_ref() { *rtv_format = auxil::dxgi::conv::map_texture_format(ct.format); @@ -1386,60 +1435,64 @@ impl crate::Device for super::Device { .map(|ds| ds.bias) .unwrap_or_default(); - let raw_rasterizer = d3d12_ty::D3D12_RASTERIZER_DESC { + let raw_rasterizer = Direct3D12::D3D12_RASTERIZER_DESC { FillMode: conv::map_polygon_mode(desc.primitive.polygon_mode), CullMode: match desc.primitive.cull_mode { - None => d3d12_ty::D3D12_CULL_MODE_NONE, - Some(wgt::Face::Front) => d3d12_ty::D3D12_CULL_MODE_FRONT, - Some(wgt::Face::Back) => d3d12_ty::D3D12_CULL_MODE_BACK, + None => Direct3D12::D3D12_CULL_MODE_NONE, + Some(wgt::Face::Front) => Direct3D12::D3D12_CULL_MODE_FRONT, + Some(wgt::Face::Back) => Direct3D12::D3D12_CULL_MODE_BACK, }, FrontCounterClockwise: match desc.primitive.front_face { - wgt::FrontFace::Cw => 0, - wgt::FrontFace::Ccw => 1, + wgt::FrontFace::Cw => Foundation::FALSE, + wgt::FrontFace::Ccw => Foundation::TRUE, }, DepthBias: bias.constant, DepthBiasClamp: bias.clamp, SlopeScaledDepthBias: bias.slope_scale, - DepthClipEnable: BOOL::from(!desc.primitive.unclipped_depth), - MultisampleEnable: BOOL::from(desc.multisample.count > 1), + DepthClipEnable: Foundation::BOOL::from(!desc.primitive.unclipped_depth), + MultisampleEnable: Foundation::BOOL::from(desc.multisample.count > 1), ForcedSampleCount: 0, - AntialiasedLineEnable: 0, + AntialiasedLineEnable: false.into(), ConservativeRaster: if desc.primitive.conservative { - d3d12_ty::D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON + Direct3D12::D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON } else { - d3d12_ty::D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF + Direct3D12::D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF }, }; - let raw_desc = d3d12_ty::D3D12_GRAPHICS_PIPELINE_STATE_DESC { - pRootSignature: desc.layout.shared.signature.as_mut_ptr(), - VS: *blob_vs.create_native_shader(), - PS: match blob_fs { - Some(ref shader) => *shader.create_native_shader(), - None => *d3d12::Shader::null(), + let raw_desc = Direct3D12::D3D12_GRAPHICS_PIPELINE_STATE_DESC { + pRootSignature: unsafe { + borrow_optional_interface_temporarily(&desc.layout.shared.signature) }, - GS: *d3d12::Shader::null(), - DS: *d3d12::Shader::null(), - HS: *d3d12::Shader::null(), - StreamOutput: d3d12_ty::D3D12_STREAM_OUTPUT_DESC { + VS: blob_vs.create_native_shader(), + PS: match &blob_fs { + Some(shader) => shader.create_native_shader(), + None => Direct3D12::D3D12_SHADER_BYTECODE::default(), + }, + GS: Direct3D12::D3D12_SHADER_BYTECODE::default(), + DS: Direct3D12::D3D12_SHADER_BYTECODE::default(), + HS: Direct3D12::D3D12_SHADER_BYTECODE::default(), + StreamOutput: Direct3D12::D3D12_STREAM_OUTPUT_DESC { pSODeclaration: ptr::null(), NumEntries: 0, pBufferStrides: ptr::null(), NumStrides: 0, RasterizedStream: 0, }, - BlendState: d3d12_ty::D3D12_BLEND_DESC { - AlphaToCoverageEnable: BOOL::from(desc.multisample.alpha_to_coverage_enabled), - IndependentBlendEnable: 1, + BlendState: Direct3D12::D3D12_BLEND_DESC { + AlphaToCoverageEnable: Foundation::BOOL::from( + desc.multisample.alpha_to_coverage_enabled, + ), + IndependentBlendEnable: true.into(), RenderTarget: conv::map_render_targets(desc.color_targets), }, SampleMask: desc.multisample.mask as u32, RasterizerState: raw_rasterizer, DepthStencilState: match desc.depth_stencil { Some(ref ds) => conv::map_depth_stencil(ds), - None => unsafe { mem::zeroed() }, + None => Default::default(), }, - InputLayout: d3d12_ty::D3D12_INPUT_LAYOUT_DESC { + InputLayout: Direct3D12::D3D12_INPUT_LAYOUT_DESC { pInputElementDescs: if input_element_descs.is_empty() { ptr::null() } else { @@ -1449,12 +1502,12 @@ impl crate::Device for super::Device { }, IBStripCutValue: match desc.primitive.strip_index_format { Some(wgt::IndexFormat::Uint16) => { - d3d12_ty::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF + Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF } Some(wgt::IndexFormat::Uint32) => { - d3d12_ty::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF + Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF } - None => d3d12_ty::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED, + None => Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED, }, PrimitiveTopologyType: topology_class, NumRenderTargets: desc.color_targets.len() as u32, @@ -1462,46 +1515,35 @@ impl crate::Device for super::Device { DSVFormat: desc .depth_stencil .as_ref() - .map_or(dxgiformat::DXGI_FORMAT_UNKNOWN, |ds| { + .map_or(Dxgi::Common::DXGI_FORMAT_UNKNOWN, |ds| { auxil::dxgi::conv::map_texture_format(ds.format) }), - SampleDesc: dxgitype::DXGI_SAMPLE_DESC { + SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { Count: desc.multisample.count, Quality: 0, }, NodeMask: 0, - CachedPSO: d3d12_ty::D3D12_CACHED_PIPELINE_STATE { + CachedPSO: Direct3D12::D3D12_CACHED_PIPELINE_STATE { pCachedBlob: ptr::null(), CachedBlobSizeInBytes: 0, }, - Flags: d3d12_ty::D3D12_PIPELINE_STATE_FLAG_NONE, + Flags: Direct3D12::D3D12_PIPELINE_STATE_FLAG_NONE, }; - let mut raw = d3d12::PipelineState::null(); - let hr = { + let raw: Direct3D12::ID3D12PipelineState = { profiling::scope!("ID3D12Device::CreateGraphicsPipelineState"); - unsafe { - self.raw.CreateGraphicsPipelineState( - &raw_desc, - &d3d12_ty::ID3D12PipelineState::uuidof(), - raw.mut_void(), - ) - } - }; + unsafe { self.raw.CreateGraphicsPipelineState(&raw_desc) } + } + .map_err(|err| crate::PipelineError::Linkage(shader_stages, err.to_string()))?; unsafe { blob_vs.destroy() }; if let Some(blob_fs) = blob_fs { unsafe { blob_fs.destroy() }; }; - hr.into_result() - .map_err(|err| crate::PipelineError::Linkage(shader_stages, err.into_owned()))?; - - null_comptr_check(&raw)?; - - if let Some(name) = desc.label { - let cwstr = conv::map_label(name); - unsafe { raw.SetName(cwstr.as_ptr()) }; + if let Some(label) = desc.label { + unsafe { raw.SetName(&windows::core::HSTRING::from(label)) } + .into_device_result("SetName")?; } self.counters.render_pipelines.add(1); @@ -1530,26 +1572,30 @@ impl crate::Device for super::Device { let pair = { profiling::scope!("ID3D12Device::CreateComputePipelineState"); - self.raw.create_compute_pipeline_state( - &desc.layout.shared.signature, - blob_cs.create_native_shader(), - 0, - d3d12::CachedPSO::null(), - d3d12::PipelineStateFlags::empty(), - ) + unsafe { + self.raw.CreateComputePipelineState( + &Direct3D12::D3D12_COMPUTE_PIPELINE_STATE_DESC { + pRootSignature: borrow_optional_interface_temporarily( + &desc.layout.shared.signature, + ), + CS: blob_cs.create_native_shader(), + NodeMask: 0, + CachedPSO: Direct3D12::D3D12_CACHED_PIPELINE_STATE::default(), + Flags: Direct3D12::D3D12_PIPELINE_STATE_FLAG_NONE, + }, + ) + } }; unsafe { blob_cs.destroy() }; - let raw = pair.into_result().map_err(|err| { - crate::PipelineError::Linkage(wgt::ShaderStages::COMPUTE, err.into_owned()) + let raw: Direct3D12::ID3D12PipelineState = pair.map_err(|err| { + crate::PipelineError::Linkage(wgt::ShaderStages::COMPUTE, err.to_string()) })?; - null_comptr_check(&raw)?; - - if let Some(name) = desc.label { - let cwstr = conv::map_label(name); - unsafe { raw.SetName(cwstr.as_ptr()) }; + if let Some(label) = desc.label { + unsafe { raw.SetName(&windows::core::HSTRING::from(label)) } + .into_device_result("SetName")?; } self.counters.compute_pipelines.add(1); @@ -1575,32 +1621,40 @@ impl crate::Device for super::Device { unsafe fn create_query_set( &self, desc: &wgt::QuerySetDescriptor, - ) -> Result { + ) -> Result { let (heap_ty, raw_ty) = match desc.ty { wgt::QueryType::Occlusion => ( - d3d12::QueryHeapType::Occlusion, - d3d12_ty::D3D12_QUERY_TYPE_BINARY_OCCLUSION, + Direct3D12::D3D12_QUERY_HEAP_TYPE_OCCLUSION, + Direct3D12::D3D12_QUERY_TYPE_BINARY_OCCLUSION, ), wgt::QueryType::PipelineStatistics(_) => ( - d3d12::QueryHeapType::PipelineStatistics, - d3d12_ty::D3D12_QUERY_TYPE_PIPELINE_STATISTICS, + Direct3D12::D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS, + Direct3D12::D3D12_QUERY_TYPE_PIPELINE_STATISTICS, ), wgt::QueryType::Timestamp => ( - d3d12::QueryHeapType::Timestamp, - d3d12_ty::D3D12_QUERY_TYPE_TIMESTAMP, + Direct3D12::D3D12_QUERY_HEAP_TYPE_TIMESTAMP, + Direct3D12::D3D12_QUERY_TYPE_TIMESTAMP, ), }; - let raw = self - .raw - .create_query_heap(heap_ty, desc.count, 0) - .into_device_result("Query heap creation")?; + let mut raw = None::; + unsafe { + self.raw.CreateQueryHeap( + &Direct3D12::D3D12_QUERY_HEAP_DESC { + Type: heap_ty, + Count: desc.count, + NodeMask: 0, + }, + &mut raw, + ) + } + .into_device_result("Query heap creation")?; - null_comptr_check(&raw)?; + let raw = raw.ok_or(crate::DeviceError::Unexpected)?; if let Some(label) = desc.label { - let cwstr = conv::map_label(label); - unsafe { raw.SetName(cwstr.as_ptr()) }; + unsafe { raw.SetName(&windows::core::HSTRING::from(label)) } + .into_device_result("SetName")?; } self.counters.query_sets.add(1); @@ -1612,18 +1666,10 @@ impl crate::Device for super::Device { self.counters.query_sets.sub(1); } - unsafe fn create_fence(&self) -> Result { - let mut raw = d3d12::Fence::null(); - let hr = unsafe { - self.raw.CreateFence( - 0, - d3d12_ty::D3D12_FENCE_FLAG_SHARED, - &d3d12_ty::ID3D12Fence::uuidof(), - raw.mut_void(), - ) - }; - hr.into_device_result("Fence creation")?; - null_comptr_check(&raw)?; + unsafe fn create_fence(&self) -> Result { + let raw: Direct3D12::ID3D12Fence = + unsafe { self.raw.CreateFence(0, Direct3D12::D3D12_FENCE_FLAG_SHARED) } + .into_device_result("Fence creation")?; self.counters.fences.add(1); @@ -1636,7 +1682,7 @@ impl crate::Device for super::Device { unsafe fn get_fence_value( &self, fence: &super::Fence, - ) -> Result { + ) -> Result { Ok(unsafe { fence.raw.GetCompletedValue() }) } unsafe fn wait( @@ -1644,7 +1690,7 @@ impl crate::Device for super::Device { fence: &super::Fence, value: crate::FenceValue, timeout_ms: u32, - ) -> Result { + ) -> Result { let timeout_duration = Duration::from_millis(timeout_ms as u64); // We first check if the fence has already reached the value we're waiting for. @@ -1653,9 +1699,7 @@ impl crate::Device for super::Device { return Ok(true); } - fence - .raw - .set_event_on_completion(self.idler.event, value) + unsafe { fence.raw.SetEventOnCompletion(value, self.idler.event.0) } .into_device_result("Set event")?; let start_time = Instant::now(); @@ -1682,7 +1726,7 @@ impl crate::Device for super::Device { let remaining_wait_duration = match timeout_duration.checked_sub(elapsed) { Some(remaining) => remaining, None => { - log::trace!("Timeout elapsed inbetween waits!"); + log::trace!("Timeout elapsed in between waits!"); break Ok(false); } }; @@ -1694,23 +1738,23 @@ impl crate::Device for super::Device { ); match unsafe { - synchapi::WaitForSingleObject( + Threading::WaitForSingleObject( self.idler.event.0, remaining_wait_duration.as_millis().try_into().unwrap(), ) } { - winbase::WAIT_OBJECT_0 => {} - winbase::WAIT_ABANDONED | winbase::WAIT_FAILED => { + Foundation::WAIT_OBJECT_0 => {} + Foundation::WAIT_ABANDONED | Foundation::WAIT_FAILED => { log::error!("Wait failed!"); - break Err(DeviceError::Lost); + break Err(crate::DeviceError::Lost); } - winerror::WAIT_TIMEOUT => { + Foundation::WAIT_TIMEOUT => { log::trace!("Wait timed out!"); break Ok(false); } other => { - log::error!("Unexpected wait status: 0x{:x}", other); - break Err(DeviceError::Lost); + log::error!("Unexpected wait status: 0x{:?}", other); + break Err(crate::DeviceError::Lost); } }; @@ -1728,7 +1772,7 @@ impl crate::Device for super::Device { { unsafe { self.render_doc - .start_frame_capture(self.raw.as_mut_ptr().cast(), ptr::null_mut()) + .start_frame_capture(self.raw.as_raw(), ptr::null_mut()) } } #[cfg(not(feature = "renderdoc"))] @@ -1739,7 +1783,7 @@ impl crate::Device for super::Device { #[cfg(feature = "renderdoc")] unsafe { self.render_doc - .end_frame_capture(self.raw.as_mut_ptr().cast(), ptr::null_mut()) + .end_frame_capture(self.raw.as_raw(), ptr::null_mut()) } } @@ -1764,7 +1808,7 @@ impl crate::Device for super::Device { unsafe fn create_acceleration_structure( &self, _desc: &crate::AccelerationStructureDescriptor, - ) -> Result { + ) -> Result { // Create a D3D12 resource as per-usual. todo!() } @@ -1781,15 +1825,8 @@ impl crate::Device for super::Device { self.counters.clone() } - #[cfg(feature = "windows_rs")] fn generate_allocator_report(&self) -> Option { - let mut upstream = { - self.mem_allocator - .as_ref()? - .lock() - .allocator - .generate_report() - }; + let mut upstream = self.mem_allocator.lock().allocator.generate_report(); let allocations = upstream .allocations diff --git a/wgpu-hal/src/dx12/instance.rs b/wgpu-hal/src/dx12/instance.rs index c9557355fb..31d0511d39 100644 --- a/wgpu-hal/src/dx12/instance.rs +++ b/wgpu-hal/src/dx12/instance.rs @@ -1,9 +1,16 @@ +use std::{mem::size_of_val, sync::Arc}; + use parking_lot::RwLock; -use winapi::shared::{dxgi1_5, minwindef}; +use windows::{ + core::Interface as _, + Win32::{ + Foundation, + Graphics::{Direct3D12, Dxgi}, + }, +}; use super::SurfaceTarget; -use crate::auxil::{self, dxgi::result::HResult as _}; -use std::{mem, sync::Arc}; +use crate::{auxil, dx12::D3D12Lib}; impl Drop for super::Instance { fn drop(&mut self) { @@ -18,7 +25,7 @@ impl crate::Instance for super::Instance { unsafe fn init(desc: &crate::InstanceDescriptor) -> Result { profiling::scope!("Init DX12 Backend"); - let lib_main = d3d12::D3D12Lib::new().map_err(|e| { + let lib_main = D3D12Lib::new().map_err(|e| { crate::InstanceError::with_source(String::from("failed to load d3d12.dll"), e) })?; @@ -27,67 +34,42 @@ impl crate::Instance for super::Instance { .intersects(wgt::InstanceFlags::VALIDATION | wgt::InstanceFlags::GPU_BASED_VALIDATION) { // Enable debug layer - match lib_main.get_debug_interface() { - Ok(pair) => match pair.into_result() { - Ok(debug_controller) => { - if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) { - debug_controller.enable_layer(); - } - if desc - .flags - .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION) - { - #[allow(clippy::collapsible_if)] - if !debug_controller.enable_gpu_based_validation() { - log::warn!("Failed to enable GPU-based validation"); - } - } - } - Err(err) => { - log::warn!("Unable to enable D3D12 debug interface: {}", err); + if let Ok(Some(debug_controller)) = lib_main.debug_interface() { + if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) { + unsafe { debug_controller.EnableDebugLayer() } + } + if desc + .flags + .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION) + { + #[allow(clippy::collapsible_if)] + if let Ok(debug1) = debug_controller.cast::() { + unsafe { debug1.SetEnableGPUBasedValidation(true) } + } else { + log::warn!("Failed to enable GPU-based validation"); } - }, - Err(err) => { - log::warn!("Debug interface function for D3D12 not found: {:?}", err); } } } - // Create DXGIFactory4 - let (lib_dxgi, factory) = auxil::dxgi::factory::create_factory( - auxil::dxgi::factory::DxgiFactoryType::Factory4, - desc.flags, - )?; + let (lib_dxgi, factory) = auxil::dxgi::factory::create_factory(desc.flags)?; // Create IDXGIFactoryMedia - let factory_media = match lib_dxgi.create_factory_media() { - Ok(pair) => match pair.into_result() { - Ok(factory_media) => Some(factory_media), - Err(err) => { - log::error!("Failed to create IDXGIFactoryMedia: {}", err); - None - } - }, - Err(err) => { - log::warn!("IDXGIFactory1 creation function not found: {:?}", err); - None - } - }; + let factory_media = lib_dxgi.create_factory_media().ok(); let mut supports_allow_tearing = false; - #[allow(trivial_casts)] if let Some(factory5) = factory.as_factory5() { - let mut allow_tearing: minwindef::BOOL = minwindef::FALSE; + let mut allow_tearing = Foundation::FALSE; let hr = unsafe { factory5.CheckFeatureSupport( - dxgi1_5::DXGI_FEATURE_PRESENT_ALLOW_TEARING, - std::ptr::from_mut(&mut allow_tearing).cast(), - mem::size_of::() as _, + Dxgi::DXGI_FEATURE_PRESENT_ALLOW_TEARING, + <*mut _>::cast(&mut allow_tearing), + size_of_val(&allow_tearing) as u32, ) }; - match hr.into_result() { - Err(err) => log::warn!("Unable to check for tearing support: {}", err), + match hr { + Err(err) => log::warn!("Unable to check for tearing support: {err}"), Ok(()) => supports_allow_tearing = true, } } @@ -134,7 +116,8 @@ impl crate::Instance for super::Instance { raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface { factory: self.factory.clone(), factory_media: self.factory_media.clone(), - target: SurfaceTarget::WndHandle(handle.hwnd.get() as *mut _), + // https://github.com/rust-windowing/raw-window-handle/issues/171 + target: SurfaceTarget::WndHandle(Foundation::HWND(handle.hwnd.get() as *mut _)), supports_allow_tearing: self.supports_allow_tearing, swap_chain: RwLock::new(None), }), diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 8401bbe1eb..0efb418135 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -44,17 +44,307 @@ mod suballocation; mod types; mod view; -use crate::auxil::{self, dxgi::result::HResult as _}; +use std::{ffi, fmt, mem, num::NonZeroU32, ops::Deref, sync::Arc}; use arrayvec::ArrayVec; use parking_lot::{Mutex, RwLock}; -use std::{ffi, fmt, mem, num::NonZeroU32, sync::Arc}; -use winapi::{ - shared::{dxgi, dxgi1_4, dxgitype, windef, winerror}, - um::{d3d12 as d3d12_ty, dcomp, synchapi, winbase, winnt}, - Interface as _, +use windows::{ + core::{Free, Interface}, + Win32::{ + Foundation, + Graphics::{Direct3D, Direct3D12, DirectComposition, Dxgi}, + System::Threading, + }, +}; + +use crate::auxil::{ + self, + dxgi::{ + factory::{DxgiAdapter, DxgiFactory}, + result::HResult, + }, }; +#[derive(Debug)] +struct DynLib { + inner: libloading::Library, +} + +impl DynLib { + unsafe fn new

(filename: P) -> Result + where + P: AsRef, + { + unsafe { libloading::Library::new(filename) }.map(|inner| Self { inner }) + } + + unsafe fn get( + &self, + symbol: &[u8], + ) -> Result, crate::DeviceError> { + unsafe { self.inner.get(symbol) }.map_err(|e| match e { + libloading::Error::GetProcAddress { .. } | libloading::Error::GetProcAddressUnknown => { + crate::DeviceError::Unexpected + } + libloading::Error::IncompatibleSize + | libloading::Error::CreateCString { .. } + | libloading::Error::CreateCStringWithTrailing { .. } => crate::hal_internal_error(e), + _ => crate::DeviceError::Unexpected, // could be unreachable!() but we prefer to be more robust + }) + } +} + +#[derive(Debug)] +struct D3D12Lib { + lib: DynLib, +} + +impl D3D12Lib { + fn new() -> Result { + unsafe { DynLib::new("d3d12.dll").map(|lib| Self { lib }) } + } + + fn create_device( + &self, + adapter: &DxgiAdapter, + feature_level: Direct3D::D3D_FEATURE_LEVEL, + ) -> Result, crate::DeviceError> { + // Calls windows::Win32::Graphics::Direct3D12::D3D12CreateDevice on d3d12.dll + type Fun = extern "system" fn( + padapter: *mut core::ffi::c_void, + minimumfeaturelevel: Direct3D::D3D_FEATURE_LEVEL, + riid: *const windows_core::GUID, + ppdevice: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT; + let func: libloading::Symbol = unsafe { self.lib.get(b"D3D12CreateDevice\0") }?; + + let mut result__: Option = None; + + let res = (func)( + adapter.as_raw(), + feature_level, + // TODO: Generic? + &Direct3D12::ID3D12Device::IID, + <*mut _>::cast(&mut result__), + ) + .ok(); + + if let Err(ref err) = res { + match err.code() { + Dxgi::DXGI_ERROR_UNSUPPORTED => return Ok(None), + Dxgi::DXGI_ERROR_DRIVER_INTERNAL_ERROR => return Err(crate::DeviceError::Lost), + _ => {} + } + } + + res.into_device_result("Device creation")?; + + result__.ok_or(crate::DeviceError::Unexpected).map(Some) + } + + fn serialize_root_signature( + &self, + version: Direct3D12::D3D_ROOT_SIGNATURE_VERSION, + parameters: &[Direct3D12::D3D12_ROOT_PARAMETER], + static_samplers: &[Direct3D12::D3D12_STATIC_SAMPLER_DESC], + flags: Direct3D12::D3D12_ROOT_SIGNATURE_FLAGS, + ) -> Result { + // Calls windows::Win32::Graphics::Direct3D12::D3D12SerializeRootSignature on d3d12.dll + type Fun = extern "system" fn( + prootsignature: *const Direct3D12::D3D12_ROOT_SIGNATURE_DESC, + version: Direct3D12::D3D_ROOT_SIGNATURE_VERSION, + ppblob: *mut *mut core::ffi::c_void, + pperrorblob: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT; + let func: libloading::Symbol = + unsafe { self.lib.get(b"D3D12SerializeRootSignature\0") }?; + + let desc = Direct3D12::D3D12_ROOT_SIGNATURE_DESC { + NumParameters: parameters.len() as _, + pParameters: parameters.as_ptr(), + NumStaticSamplers: static_samplers.len() as _, + pStaticSamplers: static_samplers.as_ptr(), + Flags: flags, + }; + + let mut blob = None; + let mut error = None::; + (func)( + &desc, + version, + <*mut _>::cast(&mut blob), + <*mut _>::cast(&mut error), + ) + .ok() + .into_device_result("Root signature serialization")?; + + if let Some(error) = error { + let error = D3DBlob(error); + log::error!( + "Root signature serialization error: {:?}", + unsafe { error.as_c_str() }.unwrap().to_str().unwrap() + ); + return Err(crate::DeviceError::Unexpected); // could be hal_usage_error or hal_internal_error + } + + blob.ok_or(crate::DeviceError::Unexpected) + } + + fn debug_interface(&self) -> Result, crate::DeviceError> { + // Calls windows::Win32::Graphics::Direct3D12::D3D12GetDebugInterface on d3d12.dll + type Fun = extern "system" fn( + riid: *const windows_core::GUID, + ppvdebug: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT; + let func: libloading::Symbol = unsafe { self.lib.get(b"D3D12GetDebugInterface\0") }?; + + let mut result__ = None; + + let res = (func)(&Direct3D12::ID3D12Debug::IID, <*mut _>::cast(&mut result__)).ok(); + + if let Err(ref err) = res { + match err.code() { + Dxgi::DXGI_ERROR_SDK_COMPONENT_MISSING => return Ok(None), + _ => {} + } + } + + res.into_device_result("GetDebugInterface")?; + + result__.ok_or(crate::DeviceError::Unexpected).map(Some) + } +} + +#[derive(Debug)] +pub(super) struct DxgiLib { + lib: DynLib, +} + +impl DxgiLib { + pub fn new() -> Result { + unsafe { DynLib::new("dxgi.dll").map(|lib| Self { lib }) } + } + + /// Will error with crate::DeviceError::Unexpected if DXGI 1.3 is not available. + pub fn debug_interface1(&self) -> Result, crate::DeviceError> { + // Calls windows::Win32::Graphics::Dxgi::DXGIGetDebugInterface1 on dxgi.dll + type Fun = extern "system" fn( + flags: u32, + riid: *const windows_core::GUID, + pdebug: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT; + let func: libloading::Symbol = unsafe { self.lib.get(b"DXGIGetDebugInterface1\0") }?; + + let mut result__ = None; + + let res = (func)(0, &Dxgi::IDXGIInfoQueue::IID, <*mut _>::cast(&mut result__)).ok(); + + if let Err(ref err) = res { + match err.code() { + Dxgi::DXGI_ERROR_SDK_COMPONENT_MISSING => return Ok(None), + _ => {} + } + } + + res.into_device_result("debug_interface1")?; + + result__.ok_or(crate::DeviceError::Unexpected).map(Some) + } + + /// Will error with crate::DeviceError::Unexpected if DXGI 1.4 is not available. + pub fn create_factory4( + &self, + factory_flags: Dxgi::DXGI_CREATE_FACTORY_FLAGS, + ) -> Result { + // Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory2 on dxgi.dll + type Fun = extern "system" fn( + flags: Dxgi::DXGI_CREATE_FACTORY_FLAGS, + riid: *const windows_core::GUID, + ppfactory: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT; + let func: libloading::Symbol = unsafe { self.lib.get(b"CreateDXGIFactory2\0") }?; + + let mut result__ = None; + + (func)( + factory_flags, + &Dxgi::IDXGIFactory4::IID, + <*mut _>::cast(&mut result__), + ) + .ok() + .into_device_result("create_factory4")?; + + result__.ok_or(crate::DeviceError::Unexpected) + } + + /// Will error with crate::DeviceError::Unexpected if DXGI 1.3 is not available. + pub fn create_factory_media(&self) -> Result { + // Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory1 on dxgi.dll + type Fun = extern "system" fn( + riid: *const windows_core::GUID, + ppfactory: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT; + let func: libloading::Symbol = unsafe { self.lib.get(b"CreateDXGIFactory1\0") }?; + + let mut result__ = None; + + // https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nn-dxgi1_3-idxgifactorymedia + (func)(&Dxgi::IDXGIFactoryMedia::IID, <*mut _>::cast(&mut result__)) + .ok() + .into_device_result("create_factory_media")?; + + result__.ok_or(crate::DeviceError::Unexpected) + } +} + +/// Create a temporary "owned" copy inside a [`mem::ManuallyDrop`] without increasing the refcount or +/// moving away the source variable. +/// +/// This is a common pattern when needing to pass interface pointers ("borrows") into Windows +/// structs. Moving/cloning ownership is impossible/inconvenient because: +/// +/// - The caller does _not_ assume ownership (and decrement the refcount at a later time); +/// - Unnecessarily increasing and decrementing the refcount; +/// - [`Drop`] destructors cannot run inside `union` structures (when the created structure is +/// implicitly dropped after a call). +/// +/// See also and +/// . +/// +/// # Safety +/// Performs a [`mem::transmute_copy()`] on a refcounted [`Interface`] type. The returned +/// [`mem::ManuallyDrop`] should _not_ be dropped. +pub unsafe fn borrow_interface_temporarily(src: &I) -> mem::ManuallyDrop> { + unsafe { mem::transmute_copy(src) } +} + +/// See [`borrow_interface_temporarily()`] +pub unsafe fn borrow_optional_interface_temporarily( + src: &Option, +) -> mem::ManuallyDrop> { + unsafe { mem::transmute_copy(src) } +} + +struct D3DBlob(Direct3D::ID3DBlob); + +impl Deref for D3DBlob { + type Target = Direct3D::ID3DBlob; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl D3DBlob { + unsafe fn as_slice(&self) -> &[u8] { + unsafe { std::slice::from_raw_parts(self.GetBufferPointer().cast(), self.GetBufferSize()) } + } + + unsafe fn as_c_str(&self) -> Result<&ffi::CStr, ffi::FromBytesUntilNulError> { + ffi::CStr::from_bytes_until_nul(unsafe { self.as_slice() }) + } +} + #[derive(Clone, Debug)] pub struct Api; @@ -116,24 +406,23 @@ const MAX_ROOT_ELEMENTS: usize = 64; const ZERO_BUFFER_SIZE: wgt::BufferAddress = 256 << 10; pub struct Instance { - factory: d3d12::DxgiFactory, - factory_media: Option, - library: Arc, + factory: DxgiFactory, + factory_media: Option, + library: Arc, supports_allow_tearing: bool, - _lib_dxgi: d3d12::DxgiLib, + _lib_dxgi: DxgiLib, flags: wgt::InstanceFlags, dxc_container: Option>, } impl Instance { - pub unsafe fn create_surface_from_visual( - &self, - visual: *mut dcomp::IDCompositionVisual, - ) -> Surface { + pub unsafe fn create_surface_from_visual(&self, visual: *mut ffi::c_void) -> Surface { + let visual = unsafe { DirectComposition::IDCompositionVisual::from_raw_borrowed(&visual) } + .expect("COM pointer should not be NULL"); Surface { factory: self.factory.clone(), factory_media: self.factory_media.clone(), - target: SurfaceTarget::Visual(unsafe { d3d12::ComPtr::from_raw(visual) }), + target: SurfaceTarget::Visual(visual.to_owned()), supports_allow_tearing: self.supports_allow_tearing, swap_chain: RwLock::new(None), } @@ -141,8 +430,12 @@ impl Instance { pub unsafe fn create_surface_from_surface_handle( &self, - surface_handle: winnt::HANDLE, + surface_handle: *mut ffi::c_void, ) -> Surface { + // TODO: We're not given ownership, so we shouldn't call HANDLE::free(). This puts an extra burden on the caller to keep it alive. + // https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle could help us, even though DirectComposition is not in the list? + // Or we make all these types owned, require an ownership transition, and replace SurfaceTargetUnsafe with SurfaceTarget. + let surface_handle = Foundation::HANDLE(surface_handle); Surface { factory: self.factory.clone(), factory_media: self.factory_media.clone(), @@ -154,14 +447,15 @@ impl Instance { pub unsafe fn create_surface_from_swap_chain_panel( &self, - swap_chain_panel: *mut types::ISwapChainPanelNative, + swap_chain_panel: *mut ffi::c_void, ) -> Surface { + let swap_chain_panel = + unsafe { types::ISwapChainPanelNative::from_raw_borrowed(&swap_chain_panel) } + .expect("COM pointer should not be NULL"); Surface { factory: self.factory.clone(), factory_media: self.factory_media.clone(), - target: SurfaceTarget::SwapChainPanel(unsafe { - d3d12::ComPtr::from_raw(swap_chain_panel) - }), + target: SurfaceTarget::SwapChainPanel(swap_chain_panel.to_owned()), supports_allow_tearing: self.supports_allow_tearing, swap_chain: RwLock::new(None), } @@ -172,11 +466,13 @@ unsafe impl Send for Instance {} unsafe impl Sync for Instance {} struct SwapChain { - raw: d3d12::ComPtr, + // TODO: Drop order frees the SWC before the raw image pointers...? + raw: Dxgi::IDXGISwapChain3, // need to associate raw image pointers with the swapchain so they can be properly released // when the swapchain is destroyed - resources: Vec, - waitable: winnt::HANDLE, + resources: Vec, + /// Handle is freed in [`Self::release_resources()`] + waitable: Foundation::HANDLE, acquired_count: usize, present_mode: wgt::PresentMode, format: wgt::TextureFormat, @@ -184,15 +480,17 @@ struct SwapChain { } enum SurfaceTarget { - WndHandle(windef::HWND), - Visual(d3d12::ComPtr), - SurfaceHandle(winnt::HANDLE), - SwapChainPanel(d3d12::ComPtr), + /// Borrowed, lifetime externally managed + WndHandle(Foundation::HWND), + Visual(DirectComposition::IDCompositionVisual), + /// Borrowed, lifetime externally managed + SurfaceHandle(Foundation::HANDLE), + SwapChainPanel(types::ISwapChainPanelNative), } pub struct Surface { - factory: d3d12::DxgiFactory, - factory_media: Option, + factory: DxgiFactory, + factory_media: Option, target: SurfaceTarget, supports_allow_tearing: bool, swap_chain: RwLock>, @@ -216,7 +514,6 @@ struct PrivateCapabilities { #[allow(unused)] heterogeneous_resource_heaps: bool, memory_architecture: MemoryArchitecture, - #[allow(unused)] // TODO: Exists until windows-rs is standard, then it can probably be removed? heap_create_not_zeroed: bool, casting_fully_typed_format_supported: bool, suballocation_supported: bool, @@ -231,12 +528,12 @@ struct Workarounds { } pub struct Adapter { - raw: d3d12::DxgiAdapter, - device: d3d12::Device, - library: Arc, + raw: DxgiAdapter, + device: Direct3D12::ID3D12Device, + library: Arc, private_caps: PrivateCapabilities, presentation_timer: auxil::dxgi::time::PresentationTimer, - //Note: this isn't used right now, but we'll need it later. + // Note: this isn't used right now, but we'll need it later. #[allow(unused)] workarounds: Workarounds, dxc_container: Option>, @@ -245,20 +542,36 @@ pub struct Adapter { unsafe impl Send for Adapter {} unsafe impl Sync for Adapter {} +struct Event(pub Foundation::HANDLE); +impl Event { + pub fn create(manual_reset: bool, initial_state: bool) -> Result { + Ok(Self( + unsafe { Threading::CreateEventA(None, manual_reset, initial_state, None) } + .into_device_result("CreateEventA")?, + )) + } +} + +impl Drop for Event { + fn drop(&mut self) { + unsafe { Foundation::HANDLE::free(&mut self.0) } + } +} + /// Helper structure for waiting for GPU. struct Idler { - fence: d3d12::Fence, - event: d3d12::Event, + fence: Direct3D12::ID3D12Fence, + event: Event, } struct CommandSignatures { - draw: d3d12::CommandSignature, - draw_indexed: d3d12::CommandSignature, - dispatch: d3d12::CommandSignature, + draw: Direct3D12::ID3D12CommandSignature, + draw_indexed: Direct3D12::ID3D12CommandSignature, + dispatch: Direct3D12::ID3D12CommandSignature, } struct DeviceShared { - zero_buffer: d3d12::Resource, + zero_buffer: Direct3D12::ID3D12Resource, cmd_signatures: CommandSignatures, heap_views: descriptor::GeneralHeap, heap_samplers: descriptor::GeneralHeap, @@ -268,8 +581,8 @@ unsafe impl Send for DeviceShared {} unsafe impl Sync for DeviceShared {} pub struct Device { - raw: d3d12::Device, - present_queue: d3d12::CommandQueue, + raw: Direct3D12::ID3D12Device, + present_queue: Direct3D12::ID3D12CommandQueue, idler: Idler, private_caps: PrivateCapabilities, shared: Arc, @@ -279,11 +592,11 @@ pub struct Device { srv_uav_pool: Mutex, sampler_pool: Mutex, // library - library: Arc, + library: Arc, #[cfg(feature = "renderdoc")] render_doc: auxil::renderdoc::RenderDoc, null_rtv_handle: descriptor::Handle, - mem_allocator: Option>, + mem_allocator: Mutex, dxc_container: Option>, counters: wgt::HalCounters, } @@ -292,8 +605,8 @@ unsafe impl Send for Device {} unsafe impl Sync for Device {} pub struct Queue { - raw: d3d12::CommandQueue, - temp_lists: Mutex>, + raw: Direct3D12::ID3D12CommandQueue, + temp_lists: Mutex>>, } unsafe impl Send for Queue {} @@ -302,7 +615,7 @@ unsafe impl Sync for Queue {} #[derive(Default)] struct Temp { marker: Vec, - barriers: Vec, + barriers: Vec, } impl Temp { @@ -313,9 +626,9 @@ impl Temp { } struct PassResolve { - src: (d3d12::Resource, u32), - dst: (d3d12::Resource, u32), - format: d3d12::Format, + src: (Direct3D12::ID3D12Resource, u32), + dst: (Direct3D12::ID3D12Resource, u32), + format: Dxgi::Common::DXGI_FORMAT, } #[derive(Clone, Copy)] @@ -328,11 +641,11 @@ enum RootElement { other: u32, }, /// Descriptor table. - Table(d3d12::GpuDescriptor), + Table(Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE), /// Descriptor for a buffer that has dynamic offset. DynamicOffsetBuffer { kind: BufferViewKind, - address: d3d12::GpuAddress, + address: Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE, }, } @@ -350,14 +663,14 @@ struct PassState { root_elements: [RootElement; MAX_ROOT_ELEMENTS], constant_data: [u32; MAX_ROOT_ELEMENTS], dirty_root_elements: u64, - vertex_buffers: [d3d12_ty::D3D12_VERTEX_BUFFER_VIEW; crate::MAX_VERTEX_BUFFERS], + vertex_buffers: [Direct3D12::D3D12_VERTEX_BUFFER_VIEW; crate::MAX_VERTEX_BUFFERS], dirty_vertex_buffers: usize, kind: PassKind, } #[test] fn test_dirty_mask() { - assert_eq!(MAX_ROOT_ELEMENTS, mem::size_of::() * 8); + assert_eq!(MAX_ROOT_ELEMENTS, u64::BITS as usize); } impl PassState { @@ -366,7 +679,7 @@ impl PassState { has_label: false, resolves: ArrayVec::new(), layout: PipelineLayoutShared { - signature: d3d12::RootSignature::null(), + signature: None, total_root_elements: 0, special_constants_root_index: None, root_constant_info: None, @@ -374,7 +687,7 @@ impl PassState { root_elements: [RootElement::Empty; MAX_ROOT_ELEMENTS], constant_data: [0; MAX_ROOT_ELEMENTS], dirty_root_elements: 0, - vertex_buffers: [unsafe { mem::zeroed() }; crate::MAX_VERTEX_BUFFERS], + vertex_buffers: [Default::default(); crate::MAX_VERTEX_BUFFERS], dirty_vertex_buffers: 0, kind: PassKind::Transfer, } @@ -387,18 +700,18 @@ impl PassState { } pub struct CommandEncoder { - allocator: d3d12::CommandAllocator, - device: d3d12::Device, + allocator: Direct3D12::ID3D12CommandAllocator, + device: Direct3D12::ID3D12Device, shared: Arc, null_rtv_handle: descriptor::Handle, - list: Option, - free_lists: Vec, + list: Option, + free_lists: Vec, pass: PassState, temp: Temp, /// If set, the end of the next render/compute pass will write a timestamp at /// the given pool & location. - end_of_pass_timer_query: Option<(d3d12::QueryHeap, u32)>, + end_of_pass_timer_query: Option<(Direct3D12::ID3D12QueryHeap, u32)>, } unsafe impl Send for CommandEncoder {} @@ -415,7 +728,7 @@ impl fmt::Debug for CommandEncoder { #[derive(Debug)] pub struct CommandBuffer { - raw: d3d12::GraphicsCommandList, + raw: Direct3D12::ID3D12GraphicsCommandList, } impl crate::DynCommandBuffer for CommandBuffer {} @@ -425,7 +738,7 @@ unsafe impl Sync for CommandBuffer {} #[derive(Debug)] pub struct Buffer { - resource: d3d12::Resource, + resource: Direct3D12::ID3D12Resource, size: wgt::BufferAddress, allocation: Option, } @@ -443,14 +756,15 @@ impl crate::BufferBinding<'_, Buffer> { } } + // TODO: Return GPU handle directly? fn resolve_address(&self) -> wgt::BufferAddress { - self.buffer.resource.gpu_virtual_address() + self.offset + (unsafe { self.buffer.resource.GetGPUVirtualAddress() }) + self.offset } } #[derive(Debug)] pub struct Texture { - resource: d3d12::Resource, + resource: Direct3D12::ID3D12Resource, format: wgt::TextureFormat, dimension: wgt::TextureDimension, size: wgt::Extent3d, @@ -496,10 +810,10 @@ impl Texture { #[derive(Debug)] pub struct TextureView { - raw_format: d3d12::Format, + raw_format: Dxgi::Common::DXGI_FORMAT, aspects: crate::FormatAspects, /// only used by resolve - target_base: (d3d12::Resource, u32), + target_base: (Direct3D12::ID3D12Resource, u32), handle_srv: Option, handle_uav: Option, handle_rtv: Option, @@ -524,8 +838,8 @@ unsafe impl Sync for Sampler {} #[derive(Debug)] pub struct QuerySet { - raw: d3d12::QueryHeap, - raw_ty: d3d12_ty::D3D12_QUERY_TYPE, + raw: Direct3D12::ID3D12QueryHeap, + raw_ty: Direct3D12::D3D12_QUERY_TYPE, } impl crate::DynQuerySet for QuerySet {} @@ -535,7 +849,7 @@ unsafe impl Sync for QuerySet {} #[derive(Debug)] pub struct Fence { - raw: d3d12::Fence, + raw: Direct3D12::ID3D12Fence, } impl crate::DynFence for Fence {} @@ -544,7 +858,7 @@ unsafe impl Send for Fence {} unsafe impl Sync for Fence {} impl Fence { - pub fn raw_fence(&self) -> &d3d12::Fence { + pub fn raw_fence(&self) -> &Direct3D12::ID3D12Fence { &self.raw } } @@ -571,7 +885,7 @@ enum BufferViewKind { pub struct BindGroup { handle_views: Option, handle_samplers: Option, - dynamic_buffers: Vec, + dynamic_buffers: Vec, } impl crate::DynBindGroup for BindGroup {} @@ -602,7 +916,7 @@ struct RootConstantInfo { #[derive(Debug, Clone)] struct PipelineLayoutShared { - signature: d3d12::RootSignature, + signature: Option, total_root_elements: RootIndex, special_constants_root_index: Option, root_constant_info: Option, @@ -631,16 +945,21 @@ pub struct ShaderModule { impl crate::DynShaderModule for ShaderModule {} pub(super) enum CompiledShader { - #[allow(unused)] - Dxc(Vec), - Fxc(d3d12::Blob), + Dxc(Direct3D::Dxc::IDxcBlob), + Fxc(Direct3D::ID3DBlob), } impl CompiledShader { - fn create_native_shader(&self) -> d3d12::Shader { - match *self { - CompiledShader::Dxc(ref shader) => d3d12::Shader::from_raw(shader), - CompiledShader::Fxc(ref shader) => d3d12::Shader::from_blob(shader), + fn create_native_shader(&self) -> Direct3D12::D3D12_SHADER_BYTECODE { + match self { + CompiledShader::Dxc(shader) => Direct3D12::D3D12_SHADER_BYTECODE { + pShaderBytecode: unsafe { shader.GetBufferPointer() }, + BytecodeLength: unsafe { shader.GetBufferSize() }, + }, + CompiledShader::Fxc(shader) => Direct3D12::D3D12_SHADER_BYTECODE { + pShaderBytecode: unsafe { shader.GetBufferPointer() }, + BytecodeLength: unsafe { shader.GetBufferSize() }, + }, } } @@ -649,9 +968,9 @@ impl CompiledShader { #[derive(Debug)] pub struct RenderPipeline { - raw: d3d12::PipelineState, + raw: Direct3D12::ID3D12PipelineState, layout: PipelineLayoutShared, - topology: d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY, + topology: Direct3D::D3D_PRIMITIVE_TOPOLOGY, vertex_strides: [Option; crate::MAX_VERTEX_BUFFERS], } @@ -662,7 +981,7 @@ unsafe impl Sync for RenderPipeline {} #[derive(Debug)] pub struct ComputePipeline { - raw: d3d12::PipelineState, + raw: Direct3D12::ID3D12PipelineState, layout: PipelineLayoutShared, } @@ -682,7 +1001,8 @@ pub struct AccelerationStructure {} impl crate::DynAccelerationStructure for AccelerationStructure {} impl SwapChain { - unsafe fn release_resources(self) -> d3d12::ComPtr { + unsafe fn release_resources(mut self) -> Dxgi::IDXGISwapChain3 { + unsafe { Foundation::HANDLE::free(&mut self.waitable) }; self.raw } @@ -692,14 +1012,14 @@ impl SwapChain { ) -> Result { let timeout_ms = match timeout { Some(duration) => duration.as_millis() as u32, - None => winbase::INFINITE, + None => Threading::INFINITE, }; - match unsafe { synchapi::WaitForSingleObject(self.waitable, timeout_ms) } { - winbase::WAIT_ABANDONED | winbase::WAIT_FAILED => Err(crate::SurfaceError::Lost), - winbase::WAIT_OBJECT_0 => Ok(true), - winerror::WAIT_TIMEOUT => Ok(false), + match unsafe { Threading::WaitForSingleObject(self.waitable, timeout_ms) } { + Foundation::WAIT_ABANDONED | Foundation::WAIT_FAILED => Err(crate::SurfaceError::Lost), + Foundation::WAIT_OBJECT_0 => Ok(true), + Foundation::WAIT_TIMEOUT => Ok(false), other => { - log::error!("Unexpected wait status: 0x{:x}", other); + log::error!("Unexpected wait status: 0x{:x?}", other); Err(crate::SurfaceError::Lost) } } @@ -714,7 +1034,7 @@ impl crate::Surface for Surface { device: &Device, config: &crate::SurfaceConfiguration, ) -> Result<(), crate::SurfaceError> { - let mut flags = dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + let mut flags = Dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; // We always set ALLOW_TEARING on the swapchain no matter // what kind of swapchain we want because ResizeBuffers // cannot change the swapchain's ALLOW_TEARING flag. @@ -722,7 +1042,7 @@ impl crate::Surface for Surface { // This does not change the behavior of the swapchain, just // allow present calls to use tearing. if self.supports_allow_tearing { - flags |= dxgi::DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + flags |= Dxgi::DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; } // While `configure`s contract ensures that no work on the GPU's main queues @@ -753,96 +1073,90 @@ impl crate::Surface for Surface { flags, ) }; - if let Err(err) = result.into_result() { - log::error!("ResizeBuffers failed: {}", err); + if let Err(err) = result { + log::error!("ResizeBuffers failed: {err}"); return Err(crate::SurfaceError::Other("window is in use")); } raw } None => { - let desc = d3d12::SwapchainDesc { - alpha_mode: auxil::dxgi::conv::map_acomposite_alpha_mode( + let desc = Dxgi::DXGI_SWAP_CHAIN_DESC1 { + AlphaMode: auxil::dxgi::conv::map_acomposite_alpha_mode( config.composite_alpha_mode, ), - width: config.extent.width, - height: config.extent.height, - format: non_srgb_format, - stereo: false, - sample: d3d12::SampleDesc { - count: 1, - quality: 0, + Width: config.extent.width, + Height: config.extent.height, + Format: non_srgb_format, + Stereo: false.into(), + SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, }, - buffer_usage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT, - buffer_count: swap_chain_buffer, - scaling: d3d12::Scaling::Stretch, - swap_effect: d3d12::SwapEffect::FlipDiscard, - flags, + BufferUsage: Dxgi::DXGI_USAGE_RENDER_TARGET_OUTPUT, + BufferCount: swap_chain_buffer, + Scaling: Dxgi::DXGI_SCALING_STRETCH, + SwapEffect: Dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD, + Flags: flags.0 as u32, }; let swap_chain1 = match self.target { SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => { - profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition"); - self.factory - .unwrap_factory2() - .create_swapchain_for_composition( - device.present_queue.as_mut_ptr().cast(), + profiling::scope!("IDXGIFactory2::CreateSwapChainForComposition"); + unsafe { + self.factory.CreateSwapChainForComposition( + &device.present_queue, &desc, + None, ) - .into_result() + } } SurfaceTarget::SurfaceHandle(handle) => { profiling::scope!( "IDXGIFactoryMedia::CreateSwapChainForCompositionSurfaceHandle" ); - self.factory_media - .clone() - .ok_or(crate::SurfaceError::Other("IDXGIFactoryMedia not found"))? - .create_swapchain_for_composition_surface_handle( - device.present_queue.as_mut_ptr().cast(), - handle, - &desc, - ) - .into_result() + unsafe { + self.factory_media + .as_ref() + .ok_or(crate::SurfaceError::Other("IDXGIFactoryMedia not found"))? + .CreateSwapChainForCompositionSurfaceHandle( + &device.present_queue, + handle, + &desc, + None, + ) + } } SurfaceTarget::WndHandle(hwnd) => { - profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd"); - self.factory - .as_factory2() - .unwrap() - .create_swapchain_for_hwnd( - device.present_queue.as_mut_ptr().cast(), + profiling::scope!("IDXGIFactory2::CreateSwapChainForHwnd"); + unsafe { + self.factory.CreateSwapChainForHwnd( + &device.present_queue, hwnd, &desc, + None, + None, ) - .into_result() + } } }; - let swap_chain1 = match swap_chain1 { - Ok(s) => s, - Err(err) => { - log::error!("SwapChain creation error: {}", err); - return Err(crate::SurfaceError::Other("swap chain creation")); - } - }; + let swap_chain1 = swap_chain1.map_err(|err| { + log::error!("SwapChain creation error: {}", err); + crate::SurfaceError::Other("swapchain creation") + })?; match &self.target { - SurfaceTarget::WndHandle(_) | &SurfaceTarget::SurfaceHandle(_) => {} + SurfaceTarget::WndHandle(_) | SurfaceTarget::SurfaceHandle(_) => {} SurfaceTarget::Visual(visual) => { - if let Err(err) = - unsafe { visual.SetContent(swap_chain1.as_unknown()) }.into_result() - { - log::error!("Unable to SetContent: {}", err); + if let Err(err) = unsafe { visual.SetContent(&swap_chain1) } { + log::error!("Unable to SetContent: {err}"); return Err(crate::SurfaceError::Other( "IDCompositionVisual::SetContent", )); } } SurfaceTarget::SwapChainPanel(swap_chain_panel) => { - if let Err(err) = - unsafe { swap_chain_panel.SetSwapChain(swap_chain1.as_ptr()) } - .into_result() - { - log::error!("Unable to SetSwapChain: {}", err); + if let Err(err) = unsafe { swap_chain_panel.SetSwapChain(&swap_chain1) } { + log::error!("Unable to SetSwapChain: {err}"); return Err(crate::SurfaceError::Other( "ISwapChainPanelNative::SetSwapChain", )); @@ -850,42 +1164,37 @@ impl crate::Surface for Surface { } } - match unsafe { swap_chain1.cast::() }.into_result() { - Ok(swap_chain3) => swap_chain3, - Err(err) => { - log::error!("Unable to cast swap chain: {}", err); - return Err(crate::SurfaceError::Other("swap chain cast to 3")); - } - } + swap_chain1.cast::().map_err(|err| { + log::error!("Unable to cast swapchain: {err}"); + crate::SurfaceError::Other("swapchain cast to version 3") + })? } }; match self.target { SurfaceTarget::WndHandle(wnd_handle) => { // Disable automatic Alt+Enter handling by DXGI. - const DXGI_MWA_NO_WINDOW_CHANGES: u32 = 1; - const DXGI_MWA_NO_ALT_ENTER: u32 = 2; unsafe { self.factory.MakeWindowAssociation( wnd_handle, - DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER, + Dxgi::DXGI_MWA_NO_WINDOW_CHANGES | Dxgi::DXGI_MWA_NO_ALT_ENTER, ) - }; + } + .into_device_result("MakeWindowAssociation")?; } SurfaceTarget::Visual(_) | SurfaceTarget::SurfaceHandle(_) | SurfaceTarget::SwapChainPanel(_) => {} } - unsafe { swap_chain.SetMaximumFrameLatency(config.maximum_frame_latency) }; + unsafe { swap_chain.SetMaximumFrameLatency(config.maximum_frame_latency) } + .into_device_result("SetMaximumFrameLatency")?; let waitable = unsafe { swap_chain.GetFrameLatencyWaitableObject() }; let mut resources = Vec::with_capacity(swap_chain_buffer as usize); for i in 0..swap_chain_buffer { - let mut resource = d3d12::Resource::null(); - unsafe { - swap_chain.GetBuffer(i, &d3d12_ty::ID3D12Resource::uuidof(), resource.mut_void()) - }; + let resource = unsafe { swap_chain.GetBuffer(i) } + .into_device_result("Failed to get swapchain buffer")?; resources.push(resource); } @@ -966,16 +1275,15 @@ impl crate::Queue for Queue { let mut temp_lists = self.temp_lists.lock(); temp_lists.clear(); for cmd_buf in command_buffers { - temp_lists.push(cmd_buf.raw.as_list()); + temp_lists.push(Some(cmd_buf.raw.clone().into())); } { profiling::scope!("ID3D12CommandQueue::ExecuteCommandLists"); - self.raw.execute_command_lists(&temp_lists); + unsafe { self.raw.ExecuteCommandLists(&temp_lists) } } - self.raw - .signal(&signal_fence.raw, signal_value) + unsafe { self.raw.Signal(&signal_fence.raw, signal_value) } .into_device_result("Signal fence")?; // Note the lack of synchronization here between the main Direct queue @@ -997,33 +1305,22 @@ impl crate::Queue for Queue { let (interval, flags) = match sc.present_mode { // We only allow immediate if ALLOW_TEARING is valid. - wgt::PresentMode::Immediate => (0, dxgi::DXGI_PRESENT_ALLOW_TEARING), - wgt::PresentMode::Mailbox => (0, 0), - wgt::PresentMode::Fifo => (1, 0), + wgt::PresentMode::Immediate => (0, Dxgi::DXGI_PRESENT_ALLOW_TEARING), + wgt::PresentMode::Mailbox => (0, Dxgi::DXGI_PRESENT::default()), + wgt::PresentMode::Fifo => (1, Dxgi::DXGI_PRESENT::default()), m => unreachable!("Cannot make surface with present mode {m:?}"), }; profiling::scope!("IDXGISwapchain3::Present"); - unsafe { sc.raw.Present(interval, flags) }; + unsafe { sc.raw.Present(interval, flags) } + .ok() + .into_device_result("Present")?; Ok(()) } unsafe fn get_timestamp_period(&self) -> f32 { - let mut frequency = 0u64; - unsafe { self.raw.GetTimestampFrequency(&mut frequency) }; + let frequency = unsafe { self.raw.GetTimestampFrequency() }.expect("GetTimestampFrequency"); (1_000_000_000.0 / frequency as f64) as f32 } } - -/// A shorthand for producing a `ResourceCreationFailed` error if a ComPtr is null. -#[inline] -pub fn null_comptr_check( - ptr: &d3d12::ComPtr, -) -> Result<(), crate::DeviceError> { - if d3d12::ComPtr::is_null(ptr) { - return Err(crate::DeviceError::ResourceCreationFailed); - } - - Ok(()) -} diff --git a/wgpu-hal/src/dx12/shader_compilation.rs b/wgpu-hal/src/dx12/shader_compilation.rs index f290861d35..e3d4d03c6c 100644 --- a/wgpu-hal/src/dx12/shader_compilation.rs +++ b/wgpu-hal/src/dx12/shader_compilation.rs @@ -1,13 +1,11 @@ -use std::ffi::CStr; -use std::ptr; - -pub(super) use dxc::{compile_dxc, get_dxc_container, DxcContainer}; -use winapi::um::d3dcompiler; - use crate::auxil::dxgi::result::HResult; +use std::ffi::CStr; +use std::path::PathBuf; +use windows::{ + core::{Interface, PCSTR, PCWSTR}, + Win32::Graphics::Direct3D::{Dxc, Fxc}, +}; -// This exists so that users who don't want to use dxc can disable the dxc_shader_compiler feature -// and not have to compile hassle_rs. // Currently this will use Dxc if it is chosen as the dx12 compiler at `Instance` creation time, and will // fallback to FXC if the Dxc libraries (dxil.dll and dxcompiler.dll) are not found, or if Fxc is chosen at' // `Instance` creation time. @@ -16,290 +14,296 @@ pub(super) fn compile_fxc( device: &super::Device, source: &str, source_name: Option<&CStr>, - raw_ep: &std::ffi::CString, + raw_ep: &str, stage_bit: wgt::ShaderStages, - full_stage: &CStr, -) -> ( - Result, - log::Level, -) { + full_stage: &str, +) -> Result { profiling::scope!("compile_fxc"); - let mut shader_data = d3d12::Blob::null(); - let mut compile_flags = d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS; + let mut shader_data = None; + let mut compile_flags = Fxc::D3DCOMPILE_ENABLE_STRICTNESS; if device .private_caps .instance_flags .contains(wgt::InstanceFlags::DEBUG) { - compile_flags |= d3dcompiler::D3DCOMPILE_DEBUG | d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION; + compile_flags |= Fxc::D3DCOMPILE_DEBUG | Fxc::D3DCOMPILE_SKIP_OPTIMIZATION; } + let raw_ep = std::ffi::CString::new(raw_ep).unwrap(); + let full_stage = std::ffi::CString::new(full_stage).unwrap(); + // If no name has been set, D3DCompile wants the null pointer. - let source_name = source_name.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()); + let source_name = source_name + .map(|cstr| cstr.as_ptr().cast()) + .unwrap_or(core::ptr::null()); - let mut error = d3d12::Blob::null(); + let mut error = None; let hr = unsafe { - profiling::scope!("d3dcompiler::D3DCompile"); - d3dcompiler::D3DCompile( + profiling::scope!("Fxc::D3DCompile"); + Fxc::D3DCompile( + // TODO: Update low-level bindings to accept a slice here source.as_ptr().cast(), source.len(), - source_name.cast(), - ptr::null(), - ptr::null_mut(), - raw_ep.as_ptr(), - full_stage.as_ptr().cast(), + PCSTR(source_name), + None, + None, + PCSTR(raw_ep.as_ptr().cast()), + PCSTR(full_stage.as_ptr().cast()), compile_flags, 0, - shader_data.mut_void().cast(), - error.mut_void().cast(), + &mut shader_data, + Some(&mut error), ) }; - match hr.into_result() { - Ok(()) => ( - Ok(super::CompiledShader::Fxc(shader_data)), - log::Level::Info, - ), + match hr { + Ok(()) => { + let shader_data = shader_data.unwrap(); + Ok(super::CompiledShader::Fxc(shader_data)) + } Err(e) => { let mut full_msg = format!("FXC D3DCompile error ({e})"); - if !error.is_null() { + if let Some(error) = error { use std::fmt::Write as _; let message = unsafe { std::slice::from_raw_parts( - error.GetBufferPointer() as *const u8, + error.GetBufferPointer().cast(), error.GetBufferSize(), ) }; let _ = write!(full_msg, ": {}", String::from_utf8_lossy(message)); } - ( - Err(crate::PipelineError::Linkage(stage_bit, full_msg)), - log::Level::Warn, - ) + Err(crate::PipelineError::Linkage(stage_bit, full_msg)) } } } -// The Dxc implementation is behind a feature flag so that users who don't want to use dxc can disable the feature. -#[cfg(feature = "dxc_shader_compiler")] -mod dxc { - use std::ffi::CStr; - use std::path::PathBuf; - - // Destructor order should be fine since _dxil and _dxc don't rely on each other. - pub(crate) struct DxcContainer { - compiler: hassle_rs::DxcCompiler, - library: hassle_rs::DxcLibrary, - validator: hassle_rs::DxcValidator, - // Has to be held onto for the lifetime of the device otherwise shaders will fail to compile. - _dxc: hassle_rs::Dxc, - // Also Has to be held onto for the lifetime of the device otherwise shaders will fail to validate. - _dxil: hassle_rs::Dxil, - } +trait DxcObj: Interface { + const CLSID: windows::core::GUID; +} +impl DxcObj for Dxc::IDxcCompiler3 { + const CLSID: windows::core::GUID = Dxc::CLSID_DxcCompiler; +} +impl DxcObj for Dxc::IDxcUtils { + const CLSID: windows::core::GUID = Dxc::CLSID_DxcUtils; +} +impl DxcObj for Dxc::IDxcValidator { + const CLSID: windows::core::GUID = Dxc::CLSID_DxcValidator; +} - pub(crate) fn get_dxc_container( - dxc_path: Option, - dxil_path: Option, - ) -> Result, crate::DeviceError> { - // Make sure that dxil.dll exists. - let dxil = match hassle_rs::Dxil::new(dxil_path) { - Ok(dxil) => dxil, - Err(e) => { - log::warn!("Failed to load dxil.dll. Defaulting to FXC instead: {}", e); - return Ok(None); - } - }; +#[derive(Debug)] +struct DxcLib { + lib: crate::dx12::DynLib, +} - // Needed for explicit validation. - let validator = dxil.create_validator()?; - - let dxc = match hassle_rs::Dxc::new(dxc_path) { - Ok(dxc) => dxc, - Err(e) => { - log::warn!( - "Failed to load dxcompiler.dll. Defaulting to FXC instead: {}", - e - ); - return Ok(None); +impl DxcLib { + fn new(lib_path: Option, lib_name: &'static str) -> Result { + let lib_path = if let Some(lib_path) = lib_path { + if lib_path.is_file() { + lib_path + } else { + lib_path.join(lib_name) } + } else { + PathBuf::from(lib_name) }; - let compiler = dxc.create_compiler()?; - let library = dxc.create_library()?; - - Ok(Some(DxcContainer { - _dxc: dxc, - compiler, - library, - _dxil: dxil, - validator, - })) + unsafe { crate::dx12::DynLib::new(lib_path).map(|lib| Self { lib }) } + } + + pub fn create_instance(&self) -> Result { + type Fun = extern "system" fn( + rclsid: *const windows_core::GUID, + riid: *const windows_core::GUID, + ppv: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT; + let func: libloading::Symbol = unsafe { self.lib.get(b"DxcCreateInstance\0") }?; + + let mut result__ = None; + (func)(&T::CLSID, &T::IID, <*mut _>::cast(&mut result__)) + .ok() + .into_device_result("DxcCreateInstance")?; + result__.ok_or(crate::DeviceError::Unexpected) } +} + +// Destructor order should be fine since _dxil and _dxc don't rely on each other. +pub(super) struct DxcContainer { + compiler: Dxc::IDxcCompiler3, + utils: Dxc::IDxcUtils, + validator: Dxc::IDxcValidator, + // Has to be held onto for the lifetime of the device otherwise shaders will fail to compile. + _dxc: DxcLib, + // Also Has to be held onto for the lifetime of the device otherwise shaders will fail to validate. + _dxil: DxcLib, +} - pub(crate) fn compile_dxc( - device: &crate::dx12::Device, - source: &str, - source_name: Option<&CStr>, - raw_ep: &str, - stage_bit: wgt::ShaderStages, - full_stage: String, - dxc_container: &DxcContainer, - ) -> ( - Result, - log::Level, - ) { - profiling::scope!("compile_dxc"); - let mut compile_flags = arrayvec::ArrayVec::<&str, 6>::new_const(); - compile_flags.push("-Ges"); // d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS - compile_flags.push("-Vd"); // Disable implicit validation to work around bugs when dxil.dll isn't in the local directory. - compile_flags.push("-HV"); // Use HLSL 2018, Naga doesn't supported 2021 yet. - compile_flags.push("2018"); - - if device - .private_caps - .instance_flags - .contains(wgt::InstanceFlags::DEBUG) - { - compile_flags.push("-Zi"); // d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION - compile_flags.push("-Od"); // d3dcompiler::D3DCOMPILE_DEBUG +pub(super) fn get_dxc_container( + dxc_path: Option, + dxil_path: Option, +) -> Result, crate::DeviceError> { + let dxc = match DxcLib::new(dxc_path, "dxcompiler.dll") { + Ok(dxc) => dxc, + Err(e) => { + log::warn!( + "Failed to load dxcompiler.dll. Defaulting to FXC instead: {}", + e + ); + return Ok(None); } + }; - let blob = match dxc_container - .library - .create_blob_with_encoding_from_str(source) - .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("DXC blob error: {e}"))) - { - Ok(blob) => blob, - Err(e) => return (Err(e), log::Level::Error), - }; + let dxil = match DxcLib::new(dxil_path, "dxil.dll") { + Ok(dxil) => dxil, + Err(e) => { + log::warn!("Failed to load dxil.dll. Defaulting to FXC instead: {}", e); + return Ok(None); + } + }; - let source_name = source_name - .and_then(|cstr| cstr.to_str().ok()) - .unwrap_or(""); + let compiler = dxc.create_instance::()?; + let utils = dxc.create_instance::()?; + let validator = dxil.create_instance::()?; - let compiled = dxc_container.compiler.compile( - &blob, - source_name, - raw_ep, - &full_stage, - &compile_flags, - None, - &[], - ); - - let (result, log_level) = match compiled { - Ok(dxc_result) => match dxc_result.get_result() { - Ok(dxc_blob) => { - // Validate the shader. - match dxc_container.validator.validate(dxc_blob) { - Ok(validated_blob) => ( - Ok(crate::dx12::CompiledShader::Dxc(validated_blob.to_vec())), - log::Level::Info, - ), - Err(e) => ( - Err(crate::PipelineError::Linkage( - stage_bit, - format!( - "DXC validation error: {:?}\n{:?}", - get_error_string_from_dxc_result(&dxc_container.library, &e.0) - .unwrap_or_default(), - e.1 - ), - )), - log::Level::Error, - ), - } - } - Err(e) => ( - Err(crate::PipelineError::Linkage( - stage_bit, - format!("DXC compile error: {e}"), - )), - log::Level::Error, - ), - }, - Err(e) => ( - Err(crate::PipelineError::Linkage( - stage_bit, - format!( - "DXC compile error: {}", - get_error_string_from_dxc_result(&dxc_container.library, &e.0) - .unwrap_or_default() - ), - )), - log::Level::Error, - ), - }; + Ok(Some(DxcContainer { + compiler, + utils, + validator, + _dxc: dxc, + _dxil: dxil, + })) +} - (result, log_level) - } +/// Owned PCWSTR +#[allow(clippy::upper_case_acronyms)] +struct OPCWSTR { + inner: Vec, +} - impl From for crate::DeviceError { - fn from(value: hassle_rs::HassleError) -> Self { - match value { - hassle_rs::HassleError::Win32Error(e) => { - // TODO: This returns an HRESULT, should we try and use the associated Windows error message? - log::error!("Win32 error: {e:?}"); - crate::DeviceError::Lost - } - hassle_rs::HassleError::LoadLibraryError { filename, inner } => { - log::error!("Failed to load dxc library {filename:?}. Inner error: {inner:?}"); - crate::DeviceError::Lost - } - hassle_rs::HassleError::LibLoadingError(e) => { - log::error!("Failed to load dxc library. {e:?}"); - crate::DeviceError::Lost - } - hassle_rs::HassleError::WindowsOnly(e) => { - log::error!("Signing with dxil.dll is only supported on Windows. {e:?}"); - crate::DeviceError::Lost - } - // `ValidationError` and `CompileError` should never happen in a context involving `DeviceError` - hassle_rs::HassleError::ValidationError(_e) => unimplemented!(), - hassle_rs::HassleError::CompileError(_e) => unimplemented!(), - } - } +impl OPCWSTR { + fn new(s: &str) -> Self { + let mut inner: Vec<_> = s.encode_utf16().collect(); + inner.push(0); + Self { inner } } - fn get_error_string_from_dxc_result( - library: &hassle_rs::DxcLibrary, - error: &hassle_rs::DxcOperationResult, - ) -> Result { - error - .get_error_buffer() - .and_then(|error| library.get_blob_as_string(&hassle_rs::DxcBlob::from(error))) + fn ptr(&self) -> PCWSTR { + PCWSTR(self.inner.as_ptr()) } } -// These are stubs for when the `dxc_shader_compiler` feature is disabled. -#[cfg(not(feature = "dxc_shader_compiler"))] -mod dxc { - use std::ffi::CStr; - use std::path::PathBuf; - - pub(crate) struct DxcContainer {} - - pub(crate) fn get_dxc_container( - _dxc_path: Option, - _dxil_path: Option, - ) -> Result, crate::DeviceError> { - // Falls back to Fxc and logs an error. - log::error!("DXC shader compiler was requested on Instance creation, but the DXC feature is disabled. Enable the `dxc_shader_compiler` feature on wgpu_hal to use DXC."); - Ok(None) +fn get_output( + res: &Dxc::IDxcResult, + kind: Dxc::DXC_OUT_KIND, +) -> Result { + let mut result__: Option = None; + unsafe { res.GetOutput::(kind, &mut None, <*mut _>::cast(&mut result__)) } + .into_device_result("GetOutput")?; + result__.ok_or(crate::DeviceError::Unexpected) +} + +fn as_err_str(blob: &Dxc::IDxcBlobUtf8) -> Result<&str, crate::DeviceError> { + let ptr = unsafe { blob.GetStringPointer() }; + let len = unsafe { blob.GetStringLength() }; + core::str::from_utf8(unsafe { core::slice::from_raw_parts(ptr.0, len) }) + .map_err(|_| crate::DeviceError::Unexpected) +} + +pub(super) fn compile_dxc( + device: &crate::dx12::Device, + source: &str, + source_name: Option<&CStr>, + raw_ep: &str, + stage_bit: wgt::ShaderStages, + full_stage: &str, + dxc_container: &DxcContainer, +) -> Result { + profiling::scope!("compile_dxc"); + + let source_name = source_name.and_then(|cstr| cstr.to_str().ok()); + + let source_name = source_name.map(OPCWSTR::new); + let raw_ep = OPCWSTR::new(raw_ep); + let full_stage = OPCWSTR::new(full_stage); + + let mut compile_args = arrayvec::ArrayVec::::new_const(); + + if let Some(source_name) = source_name.as_ref() { + compile_args.push(source_name.ptr()) + } + + compile_args.extend([ + windows::core::w!("-E"), + raw_ep.ptr(), + windows::core::w!("-T"), + full_stage.ptr(), + windows::core::w!("-HV"), + windows::core::w!("2018"), // Use HLSL 2018, Naga doesn't supported 2021 yet. + windows::core::w!("-no-warnings"), + Dxc::DXC_ARG_ENABLE_STRICTNESS, + Dxc::DXC_ARG_SKIP_VALIDATION, // Disable implicit validation to work around bugs when dxil.dll isn't in the local directory. + ]); + + if device + .private_caps + .instance_flags + .contains(wgt::InstanceFlags::DEBUG) + { + compile_args.push(Dxc::DXC_ARG_DEBUG); + compile_args.push(Dxc::DXC_ARG_SKIP_OPTIMIZATIONS); + } + + let buffer = Dxc::DxcBuffer { + Ptr: source.as_ptr().cast(), + Size: source.len(), + Encoding: Dxc::DXC_CP_UTF8.0, + }; + + let compile_res: Dxc::IDxcResult = unsafe { + dxc_container + .compiler + .Compile(&buffer, Some(&compile_args), None) } + .into_device_result("Compile")?; + + drop(compile_args); + drop(source_name); + drop(raw_ep); + drop(full_stage); + + let err_blob = get_output::(&compile_res, Dxc::DXC_OUT_ERRORS)?; - // It shouldn't be possible that this gets called with the `dxc_shader_compiler` feature disabled. - pub(crate) fn compile_dxc( - _device: &crate::dx12::Device, - _source: &str, - _source_name: Option<&CStr>, - _raw_ep: &str, - _stage_bit: wgt::ShaderStages, - _full_stage: String, - _dxc_container: &DxcContainer, - ) -> ( - Result, - log::Level, - ) { - unimplemented!("Something went really wrong, please report this. Attempted to compile shader with DXC, but the DXC feature is disabled. Enable the `dxc_shader_compiler` feature on wgpu_hal to use DXC."); + let len = unsafe { err_blob.GetStringLength() }; + if len != 0 { + let err = as_err_str(&err_blob)?; + return Err(crate::PipelineError::Linkage( + stage_bit, + format!("DXC compile error: {err}"), + )); } + + let blob = get_output::(&compile_res, Dxc::DXC_OUT_OBJECT)?; + + let err_blob = { + let res = unsafe { + dxc_container + .validator + .Validate(&blob, Dxc::DxcValidatorFlags_InPlaceEdit) + } + .into_device_result("Validate")?; + + unsafe { res.GetErrorBuffer() }.into_device_result("GetErrorBuffer")? + }; + + let size = unsafe { err_blob.GetBufferSize() }; + if size != 0 { + let err_blob = unsafe { dxc_container.utils.GetBlobAsUtf8(&err_blob) } + .into_device_result("GetBlobAsUtf8")?; + let err = as_err_str(&err_blob)?; + return Err(crate::PipelineError::Linkage( + stage_bit, + format!("DXC validation error: {err}"), + )); + } + + Ok(crate::dx12::CompiledShader::Dxc(blob)) } diff --git a/wgpu-hal/src/dx12/suballocation.rs b/wgpu-hal/src/dx12/suballocation.rs index b7ddbaf0b6..bdb3e85129 100644 --- a/wgpu-hal/src/dx12/suballocation.rs +++ b/wgpu-hal/src/dx12/suballocation.rs @@ -1,409 +1,306 @@ -pub(crate) use allocation::{ - create_allocator_wrapper, create_buffer_resource, create_texture_resource, - free_buffer_allocation, free_texture_allocation, AllocationWrapper, GpuAllocatorWrapper, -}; - -#[cfg(not(feature = "windows_rs"))] -use committed as allocation; -#[cfg(feature = "windows_rs")] -use placed as allocation; - -// This exists to work around https://github.com/gfx-rs/wgpu/issues/3207 -// Currently this will work the older, slower way if the windows_rs feature is disabled, -// and will use the fast path of suballocating buffers and textures using gpu_allocator if -// the windows_rs feature is enabled. - -// This is the fast path using gpu_allocator to suballocate buffers and textures. -#[cfg(feature = "windows_rs")] -mod placed { - use crate::dx12::null_comptr_check; - use d3d12::ComPtr; - use parking_lot::Mutex; - use std::ptr; - use wgt::assertions::StrictAssertUnwrapExt; - use winapi::{ - um::{ - d3d12::{self as d3d12_ty, ID3D12Resource}, - winnt::HRESULT, - }, - Interface, - }; +use gpu_allocator::{d3d12::AllocationCreateDesc, MemoryLocation}; +use parking_lot::Mutex; +use windows::Win32::Graphics::Direct3D12; - use gpu_allocator::{ - d3d12::{AllocationCreateDesc, ToWinapi, ToWindows}, - MemoryLocation, - }; +use crate::auxil::dxgi::result::HResult as _; - #[derive(Debug)] - pub(crate) struct GpuAllocatorWrapper { - pub(crate) allocator: gpu_allocator::d3d12::Allocator, - } +#[derive(Debug)] +pub(crate) struct GpuAllocatorWrapper { + pub(crate) allocator: gpu_allocator::d3d12::Allocator, +} - #[derive(Debug)] - pub(crate) struct AllocationWrapper { - pub(crate) allocation: gpu_allocator::d3d12::Allocation, - } +#[derive(Debug)] +pub(crate) struct AllocationWrapper { + pub(crate) allocation: gpu_allocator::d3d12::Allocation, +} - pub(crate) fn create_allocator_wrapper( - raw: &d3d12::Device, - memory_hints: &wgt::MemoryHints, - ) -> Result>, crate::DeviceError> { - let device = raw.as_ptr(); - - // TODO: the allocator's configuration should take hardware capability into - // account. - let mb = 1024 * 1024; - let allocation_sizes = match memory_hints { - wgt::MemoryHints::Performance => gpu_allocator::AllocationSizes::default(), - wgt::MemoryHints::MemoryUsage => gpu_allocator::AllocationSizes::new(8 * mb, 4 * mb), - wgt::MemoryHints::Manual { - suballocated_device_memory_block_size, - } => { - // TODO: Would it be useful to expose the host size in memory hints - // instead of always using half of the device size? - let device_size = suballocated_device_memory_block_size.start; - let host_size = device_size / 2; - gpu_allocator::AllocationSizes::new(device_size, host_size) - } - }; - - match gpu_allocator::d3d12::Allocator::new(&gpu_allocator::d3d12::AllocatorCreateDesc { - device: gpu_allocator::d3d12::ID3D12DeviceVersion::Device(device.as_windows().clone()), - debug_settings: Default::default(), - allocation_sizes, - }) { - Ok(allocator) => Ok(Some(Mutex::new(GpuAllocatorWrapper { allocator }))), - Err(e) => { - log::error!("Failed to create d3d12 allocator, error: {}", e); - Err(e)? - } +pub(crate) fn create_allocator_wrapper( + raw: &Direct3D12::ID3D12Device, + memory_hints: &wgt::MemoryHints, +) -> Result, crate::DeviceError> { + // TODO: the allocator's configuration should take hardware capability into + // account. + let mb = 1024 * 1024; + let allocation_sizes = match memory_hints { + wgt::MemoryHints::Performance => gpu_allocator::AllocationSizes::default(), + wgt::MemoryHints::MemoryUsage => gpu_allocator::AllocationSizes::new(8 * mb, 4 * mb), + wgt::MemoryHints::Manual { + suballocated_device_memory_block_size, + } => { + // TODO: Would it be useful to expose the host size in memory hints + // instead of always using half of the device size? + let device_size = suballocated_device_memory_block_size.start; + let host_size = device_size / 2; + gpu_allocator::AllocationSizes::new(device_size, host_size) } - } + }; - pub(crate) fn create_buffer_resource( - device: &crate::dx12::Device, - desc: &crate::BufferDescriptor, - raw_desc: d3d12_ty::D3D12_RESOURCE_DESC, - resource: &mut ComPtr, - ) -> Result<(HRESULT, Option), crate::DeviceError> { - let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ); - let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE); - - // It's a workaround for Intel Xe drivers. - if !device.private_caps.suballocation_supported { - return super::committed::create_buffer_resource(device, desc, raw_desc, resource) - .map(|(hr, _)| (hr, None)); + match gpu_allocator::d3d12::Allocator::new(&gpu_allocator::d3d12::AllocatorCreateDesc { + device: gpu_allocator::d3d12::ID3D12DeviceVersion::Device(raw.clone()), + debug_settings: Default::default(), + allocation_sizes, + }) { + Ok(allocator) => Ok(Mutex::new(GpuAllocatorWrapper { allocator })), + Err(e) => { + log::error!("Failed to create d3d12 allocator, error: {}", e); + Err(e)? } + } +} - let location = match (is_cpu_read, is_cpu_write) { - (true, true) => MemoryLocation::CpuToGpu, - (true, false) => MemoryLocation::GpuToCpu, - (false, true) => MemoryLocation::CpuToGpu, - (false, false) => MemoryLocation::GpuOnly, - }; - - let name = desc.label.unwrap_or("Unlabeled buffer"); - - // SAFETY: allocator exists when the windows_rs feature is enabled - let mut allocator = unsafe { - device - .mem_allocator - .as_ref() - .strict_unwrap_unchecked() - .lock() - }; - - // let mut allocator = unsafe { device.mem_allocator.as_ref().unwrap_unchecked().lock() }; - let allocation_desc = AllocationCreateDesc::from_winapi_d3d12_resource_desc( - allocator.allocator.device().as_winapi(), - &raw_desc, - name, - location, - ); - let allocation = allocator.allocator.allocate(&allocation_desc)?; - - let hr = unsafe { - device.raw.CreatePlacedResource( - allocation.heap().as_winapi() as *mut _, - allocation.offset(), - &raw_desc, - d3d12_ty::D3D12_RESOURCE_STATE_COMMON, - ptr::null(), - &ID3D12Resource::uuidof(), - resource.mut_void(), - ) - }; - - null_comptr_check(resource)?; - - device - .counters - .buffer_memory - .add(allocation.size() as isize); - - Ok((hr, Some(AllocationWrapper { allocation }))) +pub(crate) fn create_buffer_resource( + device: &crate::dx12::Device, + desc: &crate::BufferDescriptor, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, +) -> Result<(Direct3D12::ID3D12Resource, Option), crate::DeviceError> { + let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ); + let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE); + + // Workaround for Intel Xe drivers + if !device.private_caps.suballocation_supported { + return create_committed_buffer_resource(device, desc, raw_desc) + .map(|resource| (resource, None)); } - pub(crate) fn create_texture_resource( - device: &crate::dx12::Device, - desc: &crate::TextureDescriptor, - raw_desc: d3d12_ty::D3D12_RESOURCE_DESC, - resource: &mut ComPtr, - ) -> Result<(HRESULT, Option), crate::DeviceError> { - // It's a workaround for Intel Xe drivers. - if !device.private_caps.suballocation_supported { - return super::committed::create_texture_resource(device, desc, raw_desc, resource) - .map(|(hr, _)| (hr, None)); - } + let location = match (is_cpu_read, is_cpu_write) { + (true, true) => MemoryLocation::CpuToGpu, + (true, false) => MemoryLocation::GpuToCpu, + (false, true) => MemoryLocation::CpuToGpu, + (false, false) => MemoryLocation::GpuOnly, + }; + + let name = desc.label.unwrap_or("Unlabeled buffer"); - let location = MemoryLocation::GpuOnly; + let mut allocator = device.mem_allocator.lock(); - let name = desc.label.unwrap_or("Unlabeled texture"); + let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( + allocator.allocator.device(), + &raw_desc, + name, + location, + ); + let allocation = allocator.allocator.allocate(&allocation_desc)?; + let mut resource = None; - // SAFETY: allocator exists when the windows_rs feature is enabled - let mut allocator = unsafe { - device - .mem_allocator - .as_ref() - .strict_unwrap_unchecked() - .lock() - }; - let allocation_desc = AllocationCreateDesc::from_winapi_d3d12_resource_desc( - allocator.allocator.device().as_winapi(), + unsafe { + device.raw.CreatePlacedResource( + allocation.heap(), + allocation.offset(), &raw_desc, - name, - location, - ); - let allocation = allocator.allocator.allocate(&allocation_desc)?; - - let hr = unsafe { - device.raw.CreatePlacedResource( - allocation.heap().as_winapi() as *mut _, - allocation.offset(), - &raw_desc, - d3d12_ty::D3D12_RESOURCE_STATE_COMMON, - ptr::null(), // clear value - &ID3D12Resource::uuidof(), - resource.mut_void(), - ) - }; - - null_comptr_check(resource)?; - - device - .counters - .texture_memory - .add(allocation.size() as isize); - - Ok((hr, Some(AllocationWrapper { allocation }))) + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, + &mut resource, + ) } + .into_device_result("Placed buffer creation")?; + + let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + + device + .counters + .buffer_memory + .add(allocation.size() as isize); - pub(crate) fn free_buffer_allocation( - device: &crate::dx12::Device, - allocation: AllocationWrapper, - allocator: &Mutex, - ) { - device - .counters - .buffer_memory - .sub(allocation.allocation.size() as isize); - match allocator.lock().allocator.free(allocation.allocation) { - Ok(_) => (), - // TODO: Don't panic here - Err(e) => panic!("Failed to destroy dx12 buffer, {e}"), - }; + Ok((resource, Some(AllocationWrapper { allocation }))) +} + +pub(crate) fn create_texture_resource( + device: &crate::dx12::Device, + desc: &crate::TextureDescriptor, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, +) -> Result<(Direct3D12::ID3D12Resource, Option), crate::DeviceError> { + // Workaround for Intel Xe drivers + if !device.private_caps.suballocation_supported { + return create_committed_texture_resource(device, desc, raw_desc) + .map(|resource| (resource, None)); } - pub(crate) fn free_texture_allocation( - device: &crate::dx12::Device, - allocation: AllocationWrapper, - allocator: &Mutex, - ) { - device - .counters - .texture_memory - .sub(allocation.allocation.size() as isize); - match allocator.lock().allocator.free(allocation.allocation) { - Ok(_) => (), - // TODO: Don't panic here - Err(e) => panic!("Failed to destroy dx12 texture, {e}"), - }; + let location = MemoryLocation::GpuOnly; + + let name = desc.label.unwrap_or("Unlabeled texture"); + + let mut allocator = device.mem_allocator.lock(); + let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( + allocator.allocator.device(), + &raw_desc, + name, + location, + ); + let allocation = allocator.allocator.allocate(&allocation_desc)?; + let mut resource = None; + + unsafe { + device.raw.CreatePlacedResource( + allocation.heap(), + allocation.offset(), + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, // clear value + &mut resource, + ) } + .into_device_result("Placed texture creation")?; + + let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + + device + .counters + .texture_memory + .add(allocation.size() as isize); + + Ok((resource, Some(AllocationWrapper { allocation }))) +} + +pub(crate) fn free_buffer_allocation( + device: &crate::dx12::Device, + allocation: AllocationWrapper, + allocator: &Mutex, +) { + device + .counters + .buffer_memory + .sub(allocation.allocation.size() as isize); + match allocator.lock().allocator.free(allocation.allocation) { + Ok(_) => (), + // TODO: Don't panic here + Err(e) => panic!("Failed to destroy dx12 buffer, {e}"), + }; +} + +pub(crate) fn free_texture_allocation( + device: &crate::dx12::Device, + allocation: AllocationWrapper, + allocator: &Mutex, +) { + device + .counters + .texture_memory + .sub(allocation.allocation.size() as isize); + match allocator.lock().allocator.free(allocation.allocation) { + Ok(_) => (), + // TODO: Don't panic here + Err(e) => panic!("Failed to destroy dx12 texture, {e}"), + }; +} - impl From for crate::DeviceError { - fn from(result: gpu_allocator::AllocationError) -> Self { - match result { - gpu_allocator::AllocationError::OutOfMemory => Self::OutOfMemory, - gpu_allocator::AllocationError::FailedToMap(e) => { - log::error!("DX12 gpu-allocator: Failed to map: {}", e); - Self::Lost - } - gpu_allocator::AllocationError::NoCompatibleMemoryTypeFound => { - log::error!("DX12 gpu-allocator: No Compatible Memory Type Found"); - Self::Lost - } - gpu_allocator::AllocationError::InvalidAllocationCreateDesc => { - log::error!("DX12 gpu-allocator: Invalid Allocation Creation Description"); - Self::Lost - } - gpu_allocator::AllocationError::InvalidAllocatorCreateDesc(e) => { - log::error!( - "DX12 gpu-allocator: Invalid Allocator Creation Description: {}", - e - ); - Self::Lost - } - - gpu_allocator::AllocationError::Internal(e) => { - log::error!("DX12 gpu-allocator: Internal Error: {}", e); - Self::Lost - } - gpu_allocator::AllocationError::BarrierLayoutNeedsDevice10 - | gpu_allocator::AllocationError::CastableFormatsRequiresEnhancedBarriers - | gpu_allocator::AllocationError::CastableFormatsRequiresAtLeastDevice12 => { - unreachable!() - } +impl From for crate::DeviceError { + fn from(result: gpu_allocator::AllocationError) -> Self { + match result { + gpu_allocator::AllocationError::OutOfMemory => Self::OutOfMemory, + gpu_allocator::AllocationError::FailedToMap(e) => { + log::error!("DX12 gpu-allocator: Failed to map: {}", e); + Self::Lost + } + gpu_allocator::AllocationError::NoCompatibleMemoryTypeFound => { + log::error!("DX12 gpu-allocator: No Compatible Memory Type Found"); + Self::Lost + } + gpu_allocator::AllocationError::InvalidAllocationCreateDesc => { + log::error!("DX12 gpu-allocator: Invalid Allocation Creation Description"); + Self::Lost + } + gpu_allocator::AllocationError::InvalidAllocatorCreateDesc(e) => { + log::error!( + "DX12 gpu-allocator: Invalid Allocator Creation Description: {}", + e + ); + Self::Lost + } + + gpu_allocator::AllocationError::Internal(e) => { + log::error!("DX12 gpu-allocator: Internal Error: {}", e); + Self::Lost + } + gpu_allocator::AllocationError::BarrierLayoutNeedsDevice10 + | gpu_allocator::AllocationError::CastableFormatsRequiresEnhancedBarriers + | gpu_allocator::AllocationError::CastableFormatsRequiresAtLeastDevice12 => { + unreachable!() } } } } -// This is the older, slower path where it doesn't suballocate buffers. -// Tracking issue for when it can be removed: https://github.com/gfx-rs/wgpu/issues/3207 -mod committed { - use crate::dx12::null_comptr_check; - use d3d12::ComPtr; - use parking_lot::Mutex; - use std::ptr; - use winapi::{ - um::{ - d3d12::{self as d3d12_ty, ID3D12Resource}, - winnt::HRESULT, +pub(crate) fn create_committed_buffer_resource( + device: &crate::dx12::Device, + desc: &crate::BufferDescriptor, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, +) -> Result { + let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ); + let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE); + + let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { + Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, + CPUPageProperty: if is_cpu_read { + Direct3D12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK + } else if is_cpu_write { + Direct3D12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE + } else { + Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE }, - Interface, + MemoryPoolPreference: match device.private_caps.memory_architecture { + crate::dx12::MemoryArchitecture::NonUnified if !is_cpu_read && !is_cpu_write => { + Direct3D12::D3D12_MEMORY_POOL_L1 + } + _ => Direct3D12::D3D12_MEMORY_POOL_L0, + }, + CreationNodeMask: 0, + VisibleNodeMask: 0, }; - // https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_heap_flags - const D3D12_HEAP_FLAG_CREATE_NOT_ZEROED: d3d12_ty::D3D12_HEAP_FLAGS = 0x1000; - - // Allocator isn't needed when not suballocating with gpu_allocator - #[derive(Debug)] - pub(crate) struct GpuAllocatorWrapper {} - - // Allocations aren't needed when not suballocating with gpu_allocator - #[derive(Debug)] - pub(crate) struct AllocationWrapper {} + let mut resource = None; - #[allow(unused)] - pub(crate) fn create_allocator_wrapper( - _raw: &d3d12::Device, - _memory_hints: &wgt::MemoryHints, - ) -> Result>, crate::DeviceError> { - Ok(None) - } - - pub(crate) fn create_buffer_resource( - device: &crate::dx12::Device, - desc: &crate::BufferDescriptor, - raw_desc: d3d12_ty::D3D12_RESOURCE_DESC, - resource: &mut ComPtr, - ) -> Result<(HRESULT, Option), crate::DeviceError> { - let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ); - let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE); - - let heap_properties = d3d12_ty::D3D12_HEAP_PROPERTIES { - Type: d3d12_ty::D3D12_HEAP_TYPE_CUSTOM, - CPUPageProperty: if is_cpu_read { - d3d12_ty::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK - } else if is_cpu_write { - d3d12_ty::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE + unsafe { + device.raw.CreateCommittedResource( + &heap_properties, + if device.private_caps.heap_create_not_zeroed { + Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED } else { - d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE + Direct3D12::D3D12_HEAP_FLAG_NONE }, - MemoryPoolPreference: match device.private_caps.memory_architecture { - crate::dx12::MemoryArchitecture::NonUnified if !is_cpu_read && !is_cpu_write => { - d3d12_ty::D3D12_MEMORY_POOL_L1 - } - _ => d3d12_ty::D3D12_MEMORY_POOL_L0, - }, - CreationNodeMask: 0, - VisibleNodeMask: 0, - }; - - let hr = unsafe { - device.raw.CreateCommittedResource( - &heap_properties, - if device.private_caps.heap_create_not_zeroed { - D3D12_HEAP_FLAG_CREATE_NOT_ZEROED - } else { - d3d12_ty::D3D12_HEAP_FLAG_NONE - }, - &raw_desc, - d3d12_ty::D3D12_RESOURCE_STATE_COMMON, - ptr::null(), - &ID3D12Resource::uuidof(), - resource.mut_void(), - ) - }; - - null_comptr_check(resource)?; - - Ok((hr, None)) + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, + &mut resource, + ) } + .into_device_result("Committed buffer creation")?; - pub(crate) fn create_texture_resource( - device: &crate::dx12::Device, - _desc: &crate::TextureDescriptor, - raw_desc: d3d12_ty::D3D12_RESOURCE_DESC, - resource: &mut ComPtr, - ) -> Result<(HRESULT, Option), crate::DeviceError> { - let heap_properties = d3d12_ty::D3D12_HEAP_PROPERTIES { - Type: d3d12_ty::D3D12_HEAP_TYPE_CUSTOM, - CPUPageProperty: d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, - MemoryPoolPreference: match device.private_caps.memory_architecture { - crate::dx12::MemoryArchitecture::NonUnified => d3d12_ty::D3D12_MEMORY_POOL_L1, - crate::dx12::MemoryArchitecture::Unified { .. } => d3d12_ty::D3D12_MEMORY_POOL_L0, - }, - CreationNodeMask: 0, - VisibleNodeMask: 0, - }; - - let hr = unsafe { - device.raw.CreateCommittedResource( - &heap_properties, - if device.private_caps.heap_create_not_zeroed { - D3D12_HEAP_FLAG_CREATE_NOT_ZEROED - } else { - d3d12_ty::D3D12_HEAP_FLAG_NONE - }, - &raw_desc, - d3d12_ty::D3D12_RESOURCE_STATE_COMMON, - ptr::null(), // clear value - &ID3D12Resource::uuidof(), - resource.mut_void(), - ) - }; - - null_comptr_check(resource)?; - - Ok((hr, None)) - } + resource.ok_or(crate::DeviceError::Unexpected) +} - #[allow(unused)] - pub(crate) fn free_buffer_allocation( - _device: &crate::dx12::Device, - _allocation: AllocationWrapper, - _allocator: &Mutex, - ) { - // No-op when not using gpu-allocator - } +pub(crate) fn create_committed_texture_resource( + device: &crate::dx12::Device, + _desc: &crate::TextureDescriptor, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, +) -> Result { + let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { + Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, + CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, + MemoryPoolPreference: match device.private_caps.memory_architecture { + crate::dx12::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1, + crate::dx12::MemoryArchitecture::Unified { .. } => Direct3D12::D3D12_MEMORY_POOL_L0, + }, + CreationNodeMask: 0, + VisibleNodeMask: 0, + }; - #[allow(unused)] - pub(crate) fn free_texture_allocation( - _device: &crate::dx12::Device, - _allocation: AllocationWrapper, - _allocator: &Mutex, - ) { - // No-op when not using gpu-allocator + let mut resource = None; + + unsafe { + device.raw.CreateCommittedResource( + &heap_properties, + if device.private_caps.heap_create_not_zeroed { + Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED + } else { + Direct3D12::D3D12_HEAP_FLAG_NONE + }, + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, // clear value + &mut resource, + ) } + .into_device_result("Committed texture creation")?; + + resource.ok_or(crate::DeviceError::Unexpected) } diff --git a/wgpu-hal/src/dx12/types.rs b/wgpu-hal/src/dx12/types.rs index 57a0d94a85..5270c6ca8a 100644 --- a/wgpu-hal/src/dx12/types.rs +++ b/wgpu-hal/src/dx12/types.rs @@ -1,83 +1,39 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] -// use here so that the recursive RIDL macro can find the crate -use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl}; -use winapi::RIDL; - -RIDL! {#[uuid(0x63aad0b8, 0x7c24, 0x40ff, 0x85, 0xa8, 0x64, 0x0d, 0x94, 0x4c, 0xc3, 0x25)] -interface ISwapChainPanelNative(ISwapChainPanelNativeVtbl): IUnknown(IUnknownVtbl) { - fn SetSwapChain(swapChain: *const winapi::shared::dxgi1_2::IDXGISwapChain1,) -> winapi::um::winnt::HRESULT, -}} - -winapi::ENUM! { - enum D3D12_VIEW_INSTANCING_TIER { - D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED = 0, - D3D12_VIEW_INSTANCING_TIER_1 = 1, - D3D12_VIEW_INSTANCING_TIER_2 = 2, - D3D12_VIEW_INSTANCING_TIER_3 = 3, - } -} - -winapi::ENUM! { - enum D3D12_COMMAND_LIST_SUPPORT_FLAGS { - D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE = 0, - // D3D12_COMMAND_LIST_SUPPORT_FLAG_DIRECT, - // D3D12_COMMAND_LIST_SUPPORT_FLAG_BUNDLE, - // D3D12_COMMAND_LIST_SUPPORT_FLAG_COMPUTE, - // D3D12_COMMAND_LIST_SUPPORT_FLAG_COPY, - // D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_DECODE, - // D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_PROCESS, - // D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_ENCODE, +use windows::Win32::Graphics::Dxgi; + +windows_core::imp::define_interface!( + ISwapChainPanelNative, + ISwapChainPanelNative_Vtbl, + 0x63aad0b8_7c24_40ff_85a8_640d944cc325 +); +impl core::ops::Deref for ISwapChainPanelNative { + type Target = windows_core::IUnknown; + fn deref(&self) -> &Self::Target { + unsafe { core::mem::transmute(self) } } } - -winapi::STRUCT! { - struct D3D12_FEATURE_DATA_D3D12_OPTIONS3 { - CopyQueueTimestampQueriesSupported: winapi::shared::minwindef::BOOL, - CastingFullyTypedFormatSupported: winapi::shared::minwindef::BOOL, - WriteBufferImmediateSupportFlags: D3D12_COMMAND_LIST_SUPPORT_FLAGS, - ViewInstancingTier: D3D12_VIEW_INSTANCING_TIER, - BarycentricsSupported: winapi::shared::minwindef::BOOL, - } -} - -winapi::ENUM! { - enum D3D12_WAVE_MMA_TIER { - D3D12_WAVE_MMA_TIER_NOT_SUPPORTED = 0, - D3D12_WAVE_MMA_TIER_1_0 = 10, +windows_core::imp::interface_hierarchy!(ISwapChainPanelNative, windows_core::IUnknown); +impl ISwapChainPanelNative { + pub unsafe fn SetSwapChain(&self, swap_chain: P0) -> windows_core::Result<()> + where + P0: windows_core::Param, + { + unsafe { + (windows_core::Interface::vtable(self).SetSwapChain)( + windows_core::Interface::as_raw(self), + swap_chain.param().abi(), + ) + } + .ok() } } - -winapi::STRUCT! { - struct D3D12_FEATURE_DATA_D3D12_OPTIONS9 { - MeshShaderPipelineStatsSupported: winapi::shared::minwindef::BOOL, - MeshShaderSupportsFullRangeRenderTargetArrayIndex: winapi::shared::minwindef::BOOL, - AtomicInt64OnTypedResourceSupported: winapi::shared::minwindef::BOOL, - AtomicInt64OnGroupSharedSupported: winapi::shared::minwindef::BOOL, - DerivativesInMeshAndAmplificationShadersSupported: winapi::shared::minwindef::BOOL, - WaveMMATier: D3D12_WAVE_MMA_TIER, - } -} - -winapi::ENUM! { - enum D3D_SHADER_MODEL { - D3D_SHADER_MODEL_NONE = 0, - D3D_SHADER_MODEL_5_1 = 0x51, - D3D_SHADER_MODEL_6_0 = 0x60, - D3D_SHADER_MODEL_6_1 = 0x61, - D3D_SHADER_MODEL_6_2 = 0x62, - D3D_SHADER_MODEL_6_3 = 0x63, - D3D_SHADER_MODEL_6_4 = 0x64, - D3D_SHADER_MODEL_6_5 = 0x65, - D3D_SHADER_MODEL_6_6 = 0x66, - D3D_SHADER_MODEL_6_7 = 0x67, - D3D_HIGHEST_SHADER_MODEL = 0x67, - } -} - -winapi::STRUCT! { - struct D3D12_FEATURE_DATA_SHADER_MODEL { - HighestShaderModel: D3D_SHADER_MODEL, - } +#[repr(C)] +pub struct ISwapChainPanelNative_Vtbl { + pub base__: windows_core::IUnknown_Vtbl, + pub SetSwapChain: unsafe extern "system" fn( + swap_chain_panel_native: *mut core::ffi::c_void, + swap_chain: *mut core::ffi::c_void, + ) -> windows_core::HRESULT, } diff --git a/wgpu-hal/src/dx12/view.rs b/wgpu-hal/src/dx12/view.rs index ae8e5814a8..8162b012af 100644 --- a/wgpu-hal/src/dx12/view.rs +++ b/wgpu-hal/src/dx12/view.rs @@ -1,14 +1,12 @@ -use crate::auxil; -use std::mem; -use winapi::um::d3d12 as d3d12_ty; +use windows::Win32::Graphics::{Direct3D12, Dxgi}; -pub(crate) const D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING: u32 = 0x1688; +use crate::auxil; pub(super) struct ViewDescriptor { dimension: wgt::TextureViewDimension, pub aspects: crate::FormatAspects, - pub rtv_dsv_format: d3d12::Format, - srv_uav_format: Option, + pub rtv_dsv_format: Dxgi::Common::DXGI_FORMAT, + srv_uav_format: Option, multisampled: bool, array_layer_base: u32, array_layer_count: u32, @@ -44,113 +42,98 @@ fn aspects_to_plane(aspects: crate::FormatAspects) -> u32 { } impl ViewDescriptor { - pub(crate) unsafe fn to_srv(&self) -> Option { - let mut desc = d3d12_ty::D3D12_SHADER_RESOURCE_VIEW_DESC { + pub(crate) unsafe fn to_srv(&self) -> Option { + let mut desc = Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC { Format: self.srv_uav_format?, - ViewDimension: 0, - Shader4ComponentMapping: D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, - u: unsafe { mem::zeroed() }, + ViewDimension: Direct3D12::D3D12_SRV_DIMENSION_UNKNOWN, + Shader4ComponentMapping: Direct3D12::D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, + Anonymous: Default::default(), }; match self.dimension { wgt::TextureViewDimension::D1 => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE1D; - unsafe { - *desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_SRV { - MostDetailedMip: self.mip_level_base, - MipLevels: self.mip_level_count, - ResourceMinLODClamp: 0.0, - } + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE1D; + desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_SRV { + MostDetailedMip: self.mip_level_base, + MipLevels: self.mip_level_count, + ResourceMinLODClamp: 0.0, } } /* wgt::TextureViewDimension::D1Array => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE1DARRAY; - *desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_SRV { + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_SRV { MostDetailedMip: self.mip_level_base, MipLevels: self.mip_level_count, FirstArraySlice: self.array_layer_base, ArraySize: self.array_layer_count, ResourceMinLODClamp: 0.0, } - }*/ + } + */ wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DMS; - unsafe { - *desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_SRV { - UnusedField_NothingToDefine: 0, - } + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DMS; + desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_SRV { + UnusedField_NothingToDefine: 0, } } wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2D; - unsafe { - *desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_SRV { - MostDetailedMip: self.mip_level_base, - MipLevels: self.mip_level_count, - PlaneSlice: aspects_to_plane(self.aspects), - ResourceMinLODClamp: 0.0, - } + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2D; + desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_SRV { + MostDetailedMip: self.mip_level_base, + MipLevels: self.mip_level_count, + PlaneSlice: aspects_to_plane(self.aspects), + ResourceMinLODClamp: 0.0, } } wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array if self.multisampled => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY; - unsafe { - *desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_SRV { - FirstArraySlice: self.array_layer_base, - ArraySize: self.array_layer_count, - } + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY; + desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_SRV { + FirstArraySlice: self.array_layer_base, + ArraySize: self.array_layer_count, } } wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DARRAY; - unsafe { - *desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_SRV { - MostDetailedMip: self.mip_level_base, - MipLevels: self.mip_level_count, - FirstArraySlice: self.array_layer_base, - ArraySize: self.array_layer_count, - PlaneSlice: aspects_to_plane(self.aspects), - ResourceMinLODClamp: 0.0, - } + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_SRV { + MostDetailedMip: self.mip_level_base, + MipLevels: self.mip_level_count, + FirstArraySlice: self.array_layer_base, + ArraySize: self.array_layer_count, + PlaneSlice: aspects_to_plane(self.aspects), + ResourceMinLODClamp: 0.0, } } wgt::TextureViewDimension::D3 => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE3D; - unsafe { - *desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_SRV { - MostDetailedMip: self.mip_level_base, - MipLevels: self.mip_level_count, - ResourceMinLODClamp: 0.0, - } + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE3D; + desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_SRV { + MostDetailedMip: self.mip_level_base, + MipLevels: self.mip_level_count, + ResourceMinLODClamp: 0.0, } } wgt::TextureViewDimension::Cube if self.array_layer_base == 0 => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURECUBE; - unsafe { - *desc.u.TextureCube_mut() = d3d12_ty::D3D12_TEXCUBE_SRV { - MostDetailedMip: self.mip_level_base, - MipLevels: self.mip_level_count, - ResourceMinLODClamp: 0.0, - } + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURECUBE; + desc.Anonymous.TextureCube = Direct3D12::D3D12_TEXCUBE_SRV { + MostDetailedMip: self.mip_level_base, + MipLevels: self.mip_level_count, + ResourceMinLODClamp: 0.0, } } wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => { - desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; - unsafe { - *desc.u.TextureCubeArray_mut() = d3d12_ty::D3D12_TEXCUBE_ARRAY_SRV { - MostDetailedMip: self.mip_level_base, - MipLevels: self.mip_level_count, - First2DArrayFace: self.array_layer_base, - NumCubes: if self.array_layer_count == !0 { - !0 - } else { - self.array_layer_count / 6 - }, - ResourceMinLODClamp: 0.0, - } + desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; + desc.Anonymous.TextureCubeArray = Direct3D12::D3D12_TEXCUBE_ARRAY_SRV { + MostDetailedMip: self.mip_level_base, + MipLevels: self.mip_level_count, + First2DArrayFace: self.array_layer_base, + NumCubes: if self.array_layer_count == !0 { + !0 + } else { + self.array_layer_count / 6 + }, + ResourceMinLODClamp: 0.0, } } } @@ -158,59 +141,51 @@ impl ViewDescriptor { Some(desc) } - pub(crate) unsafe fn to_uav(&self) -> Option { - let mut desc = d3d12_ty::D3D12_UNORDERED_ACCESS_VIEW_DESC { + pub(crate) unsafe fn to_uav(&self) -> Option { + let mut desc = Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC { Format: self.srv_uav_format?, - ViewDimension: 0, - u: unsafe { mem::zeroed() }, + ViewDimension: Direct3D12::D3D12_UAV_DIMENSION_UNKNOWN, + Anonymous: Default::default(), }; match self.dimension { wgt::TextureViewDimension::D1 => { - desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE1D; - unsafe { - *desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_UAV { - MipSlice: self.mip_level_base, - } + desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE1D; + desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_UAV { + MipSlice: self.mip_level_base, } } /* wgt::TextureViewDimension::D1Array => { - desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE1DARRAY; - *desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_UAV { + desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE1DARRAY; + desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_UAV { MipSlice: self.mip_level_base, FirstArraySlice: self.array_layer_base, ArraySize, } }*/ wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => { - desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE2D; - unsafe { - *desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_UAV { - MipSlice: self.mip_level_base, - PlaneSlice: aspects_to_plane(self.aspects), - } + desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE2D; + desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_UAV { + MipSlice: self.mip_level_base, + PlaneSlice: aspects_to_plane(self.aspects), } } wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => { - desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE2DARRAY; - unsafe { - *desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_UAV { - MipSlice: self.mip_level_base, - FirstArraySlice: self.array_layer_base, - ArraySize: self.array_layer_count, - PlaneSlice: aspects_to_plane(self.aspects), - } + desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE2DARRAY; + desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_UAV { + MipSlice: self.mip_level_base, + FirstArraySlice: self.array_layer_base, + ArraySize: self.array_layer_count, + PlaneSlice: aspects_to_plane(self.aspects), } } wgt::TextureViewDimension::D3 => { - desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE3D; - unsafe { - *desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_UAV { - MipSlice: self.mip_level_base, - FirstWSlice: self.array_layer_base, - WSize: self.array_layer_count, - } + desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE3D; + desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_UAV { + MipSlice: self.mip_level_base, + FirstWSlice: self.array_layer_base, + WSize: self.array_layer_count, } } wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => { @@ -221,78 +196,66 @@ impl ViewDescriptor { Some(desc) } - pub(crate) unsafe fn to_rtv(&self) -> d3d12_ty::D3D12_RENDER_TARGET_VIEW_DESC { - let mut desc = d3d12_ty::D3D12_RENDER_TARGET_VIEW_DESC { + pub(crate) unsafe fn to_rtv(&self) -> Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC { + let mut desc = Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC { Format: self.rtv_dsv_format, - ViewDimension: 0, - u: unsafe { mem::zeroed() }, + ViewDimension: Direct3D12::D3D12_RTV_DIMENSION_UNKNOWN, + Anonymous: Default::default(), }; match self.dimension { wgt::TextureViewDimension::D1 => { - desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE1D; - unsafe { - *desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_RTV { - MipSlice: self.mip_level_base, - } + desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE1D; + desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_RTV { + MipSlice: self.mip_level_base, } } /* wgt::TextureViewDimension::D1Array => { - desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE1DARRAY; - *desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_RTV { + desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE1DARRAY; + desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_RTV { MipSlice: self.mip_level_base, FirstArraySlice: self.array_layer_base, ArraySize, } }*/ wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => { - desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DMS; - unsafe { - *desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_RTV { - UnusedField_NothingToDefine: 0, - } + desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DMS; + desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_RTV { + UnusedField_NothingToDefine: 0, } } wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => { - desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2D; - unsafe { - *desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_RTV { - MipSlice: self.mip_level_base, - PlaneSlice: aspects_to_plane(self.aspects), - } + desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2D; + desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_RTV { + MipSlice: self.mip_level_base, + PlaneSlice: aspects_to_plane(self.aspects), } } wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array if self.multisampled => { - desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY; - unsafe { - *desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_RTV { - FirstArraySlice: self.array_layer_base, - ArraySize: self.array_layer_count, - } + desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY; + desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_RTV { + FirstArraySlice: self.array_layer_base, + ArraySize: self.array_layer_count, } } wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => { - desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DARRAY; - unsafe { - *desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_RTV { - MipSlice: self.mip_level_base, - FirstArraySlice: self.array_layer_base, - ArraySize: self.array_layer_count, - PlaneSlice: aspects_to_plane(self.aspects), - } + desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DARRAY; + desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_RTV { + MipSlice: self.mip_level_base, + FirstArraySlice: self.array_layer_base, + ArraySize: self.array_layer_count, + PlaneSlice: aspects_to_plane(self.aspects), } } wgt::TextureViewDimension::D3 => { - desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE3D; - unsafe { - *desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_RTV { - MipSlice: self.mip_level_base, - FirstWSlice: self.array_layer_base, - WSize: self.array_layer_count, - } + desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE3D; + desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_RTV { + MipSlice: self.mip_level_base, + FirstWSlice: self.array_layer_base, + WSize: self.array_layer_count, } } wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => { @@ -303,78 +266,72 @@ impl ViewDescriptor { desc } - pub(crate) unsafe fn to_dsv(&self, read_only: bool) -> d3d12_ty::D3D12_DEPTH_STENCIL_VIEW_DESC { - let mut desc = d3d12_ty::D3D12_DEPTH_STENCIL_VIEW_DESC { + pub(crate) unsafe fn to_dsv( + &self, + read_only: bool, + ) -> Direct3D12::D3D12_DEPTH_STENCIL_VIEW_DESC { + let mut desc = Direct3D12::D3D12_DEPTH_STENCIL_VIEW_DESC { Format: self.rtv_dsv_format, - ViewDimension: 0, + ViewDimension: Direct3D12::D3D12_DSV_DIMENSION_UNKNOWN, Flags: { - let mut flags = d3d12_ty::D3D12_DSV_FLAG_NONE; + let mut flags = Direct3D12::D3D12_DSV_FLAG_NONE; if read_only { if self.aspects.contains(crate::FormatAspects::DEPTH) { - flags |= d3d12_ty::D3D12_DSV_FLAG_READ_ONLY_DEPTH; + flags |= Direct3D12::D3D12_DSV_FLAG_READ_ONLY_DEPTH; } if self.aspects.contains(crate::FormatAspects::STENCIL) { - flags |= d3d12_ty::D3D12_DSV_FLAG_READ_ONLY_STENCIL; + flags |= Direct3D12::D3D12_DSV_FLAG_READ_ONLY_STENCIL; } } flags }, - u: unsafe { mem::zeroed() }, + Anonymous: Default::default(), }; match self.dimension { wgt::TextureViewDimension::D1 => { - desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE1D; - unsafe { - *desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_DSV { - MipSlice: self.mip_level_base, - } + desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE1D; + desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_DSV { + MipSlice: self.mip_level_base, } } /* wgt::TextureViewDimension::D1Array => { - desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE1DARRAY; - *desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_DSV { + desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE1DARRAY; + desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_DSV { MipSlice: self.mip_level_base, FirstArraySlice: self.array_layer_base, ArraySize, } }*/ wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => { - desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DMS; - unsafe { - *desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_DSV { - UnusedField_NothingToDefine: 0, - } + desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DMS; + desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_DSV { + UnusedField_NothingToDefine: 0, } } wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => { - desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2D; - unsafe { - *desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_DSV { - MipSlice: self.mip_level_base, - } + desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2D; + + desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_DSV { + MipSlice: self.mip_level_base, } } wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array if self.multisampled => { - desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY; - unsafe { - *desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_DSV { - FirstArraySlice: self.array_layer_base, - ArraySize: self.array_layer_count, - } + desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY; + desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_DSV { + FirstArraySlice: self.array_layer_base, + ArraySize: self.array_layer_count, } } wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => { - desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DARRAY; - unsafe { - *desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_DSV { - MipSlice: self.mip_level_base, - FirstArraySlice: self.array_layer_base, - ArraySize: self.array_layer_count, - } + desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DARRAY; + desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_DSV { + MipSlice: self.mip_level_base, + FirstArraySlice: self.array_layer_base, + ArraySize: self.array_layer_count, } } wgt::TextureViewDimension::D3 diff --git a/wgpu-hal/src/dynamic/command.rs b/wgpu-hal/src/dynamic/command.rs index 6c0f1cb02d..4ecdf74723 100644 --- a/wgpu-hal/src/dynamic/command.rs +++ b/wgpu-hal/src/dynamic/command.rs @@ -61,7 +61,7 @@ pub trait DynCommandEncoder: DynResource + std::fmt::Debug { &mut self, layout: &dyn DynPipelineLayout, index: u32, - group: &dyn DynBindGroup, + group: Option<&dyn DynBindGroup>, dynamic_offsets: &[wgt::DynamicOffset], ); @@ -282,9 +282,15 @@ impl DynCommandEncoder for C { &mut self, layout: &dyn DynPipelineLayout, index: u32, - group: &dyn DynBindGroup, + group: Option<&dyn DynBindGroup>, dynamic_offsets: &[wgt::DynamicOffset], ) { + if group.is_none() { + // TODO: Handle group None correctly. + return; + } + let group = group.unwrap(); + let layout = layout.expect_downcast_ref(); let group = group.expect_downcast_ref(); unsafe { C::set_bind_group(self, layout, index, group, dynamic_offsets) }; diff --git a/wgpu-hal/src/dynamic/device.rs b/wgpu-hal/src/dynamic/device.rs index c1baf5b76d..f044a001de 100644 --- a/wgpu-hal/src/dynamic/device.rs +++ b/wgpu-hal/src/dynamic/device.rs @@ -1,6 +1,3 @@ -// Box casts are needed, alternative would be a temporaries which are more verbose and not more expressive. -#![allow(trivial_casts)] - use crate::{ AccelerationStructureBuildSizes, AccelerationStructureDescriptor, Api, BindGroupDescriptor, BindGroupLayoutDescriptor, BufferDescriptor, BufferMapping, CommandEncoderDescriptor, @@ -27,6 +24,7 @@ pub trait DynDevice: DynResource { ) -> Result, DeviceError>; unsafe fn destroy_buffer(&self, buffer: Box); + unsafe fn add_raw_buffer(&self, buffer: &dyn DynBuffer); unsafe fn map_buffer( &self, @@ -44,6 +42,8 @@ pub trait DynDevice: DynResource { desc: &TextureDescriptor, ) -> Result, DeviceError>; unsafe fn destroy_texture(&self, texture: Box); + unsafe fn add_raw_texture(&self, texture: &dyn DynTexture); + unsafe fn create_texture_view( &self, texture: &dyn DynTexture, @@ -180,6 +180,10 @@ impl DynDevice for D { unsafe fn destroy_buffer(&self, buffer: Box) { unsafe { D::destroy_buffer(self, buffer.unbox()) }; } + unsafe fn add_raw_buffer(&self, buffer: &dyn DynBuffer) { + let buffer = buffer.expect_downcast_ref(); + unsafe { D::add_raw_buffer(self, buffer) }; + } unsafe fn map_buffer( &self, @@ -220,6 +224,11 @@ impl DynDevice for D { unsafe { D::destroy_texture(self, texture.unbox()) }; } + unsafe fn add_raw_texture(&self, texture: &dyn DynTexture) { + let texture = texture.expect_downcast_ref(); + unsafe { D::add_raw_texture(self, texture) }; + } + unsafe fn create_texture_view( &self, texture: &dyn DynTexture, @@ -261,7 +270,7 @@ impl DynDevice for D { queue: desc.queue.expect_downcast_ref(), }; unsafe { D::create_command_encoder(self, &desc) } - .map(|b| Box::new(b) as Box) + .map(|b| -> Box { Box::new(b) }) } unsafe fn destroy_command_encoder(&self, encoder: Box) { @@ -273,7 +282,7 @@ impl DynDevice for D { desc: &BindGroupLayoutDescriptor, ) -> Result, DeviceError> { unsafe { D::create_bind_group_layout(self, desc) } - .map(|b| Box::new(b) as Box) + .map(|b| -> Box { Box::new(b) }) } unsafe fn destroy_bind_group_layout(&self, bg_layout: Box) { @@ -297,7 +306,7 @@ impl DynDevice for D { }; unsafe { D::create_pipeline_layout(self, &desc) } - .map(|b| Box::new(b) as Box) + .map(|b| -> Box { Box::new(b) }) } unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Box) { @@ -345,7 +354,8 @@ impl DynDevice for D { acceleration_structures: &acceleration_structures, }; - unsafe { D::create_bind_group(self, &desc) }.map(|b| Box::new(b) as Box) + unsafe { D::create_bind_group(self, &desc) } + .map(|b| -> Box { Box::new(b) }) } unsafe fn destroy_bind_group(&self, group: Box) { @@ -358,7 +368,7 @@ impl DynDevice for D { shader: ShaderInput, ) -> Result, ShaderError> { unsafe { D::create_shader_module(self, desc, shader) } - .map(|b| Box::new(b) as Box) + .map(|b| -> Box { Box::new(b) }) } unsafe fn destroy_shader_module(&self, module: Box) { @@ -388,7 +398,7 @@ impl DynDevice for D { }; unsafe { D::create_render_pipeline(self, &desc) } - .map(|b| Box::new(b) as Box) + .map(|b| -> Box { Box::new(b) }) } unsafe fn destroy_render_pipeline(&self, pipeline: Box) { @@ -411,7 +421,7 @@ impl DynDevice for D { }; unsafe { D::create_compute_pipeline(self, &desc) } - .map(|b| Box::new(b) as Box) + .map(|b| -> Box { Box::new(b) }) } unsafe fn destroy_compute_pipeline(&self, pipeline: Box) { @@ -423,7 +433,7 @@ impl DynDevice for D { desc: &PipelineCacheDescriptor<'_>, ) -> Result, PipelineCacheError> { unsafe { D::create_pipeline_cache(self, desc) } - .map(|b| Box::new(b) as Box) + .map(|b| -> Box { Box::new(b) }) } fn pipeline_cache_validation_key(&self) -> Option<[u8; 16]> { @@ -438,7 +448,7 @@ impl DynDevice for D { &self, desc: &wgt::QuerySetDescriptor