330: New swapchain model r=grovesNL a=kvark

Fixes #322
TODO:
- [x] Test on Metal
- [x] Test on DX12
- [x] Test on Vulkan
- [x] Try embedding the backend information into `SwapChainId`
- [x] Wait for https://github.com/amethyst/rendy/pull/202

Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
bors[bot] 2019-09-10 00:55:24 +00:00 committed by GitHub
commit 499bf1d268
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 509 additions and 765 deletions

72
Cargo.lock generated
View File

@ -254,13 +254,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gfx-backend-dx11"
version = "0.3.0"
source = "git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019#a084a1f2fec6c9ed928c53e2dc8c1761782b9019"
source = "git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69#3d5db15661127c8cad8d85522a68ec36c82f6e69"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"range-alloc 0.1.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"range-alloc 0.1.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"spirv_cross 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@ -270,13 +270,13 @@ dependencies = [
[[package]]
name = "gfx-backend-dx12"
version = "0.3.0"
source = "git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019#a084a1f2fec6c9ed928c53e2dc8c1761782b9019"
source = "git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69#3d5db15661127c8cad8d85522a68ec36c82f6e69"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"d3d12 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"range-alloc 0.1.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"range-alloc 0.1.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"spirv_cross 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@ -285,15 +285,15 @@ dependencies = [
[[package]]
name = "gfx-backend-empty"
version = "0.3.0"
source = "git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019#a084a1f2fec6c9ed928c53e2dc8c1761782b9019"
source = "git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69#3d5db15661127c8cad8d85522a68ec36c82f6e69"
dependencies = [
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
]
[[package]]
name = "gfx-backend-metal"
version = "0.3.2"
source = "git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019#a084a1f2fec6c9ed928c53e2dc8c1761782b9019"
source = "git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69#3d5db15661127c8cad8d85522a68ec36c82f6e69"
dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -302,12 +302,12 @@ dependencies = [
"copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"metal 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"range-alloc 0.1.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"range-alloc 0.1.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"spirv_cross 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"storage-map 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -316,13 +316,13 @@ dependencies = [
[[package]]
name = "gfx-backend-vulkan"
version = "0.3.0"
source = "git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019#a084a1f2fec6c9ed928c53e2dc8c1761782b9019"
source = "git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69#3d5db15661127c8cad8d85522a68ec36c82f6e69"
dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ash 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -334,7 +334,7 @@ dependencies = [
[[package]]
name = "gfx-hal"
version = "0.3.0"
source = "git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019#a084a1f2fec6c9ed928c53e2dc8c1761782b9019"
source = "git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69#3d5db15661127c8cad8d85522a68ec36c82f6e69"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -643,7 +643,7 @@ dependencies = [
[[package]]
name = "range-alloc"
version = "0.1.0"
source = "git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019#a084a1f2fec6c9ed928c53e2dc8c1761782b9019"
source = "git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69#3d5db15661127c8cad8d85522a68ec36c82f6e69"
[[package]]
name = "raw-window-handle"
@ -687,11 +687,11 @@ dependencies = [
[[package]]
name = "rendy-descriptor"
version = "0.4.0"
source = "git+https://github.com/amethyst/rendy?rev=a8ac0de977a28d09592d615f8857461622833443#a8ac0de977a28d09592d615f8857461622833443"
source = "git+https://github.com/amethyst/rendy?rev=e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86#e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86"
dependencies = [
"derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"relevant 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -700,12 +700,12 @@ dependencies = [
[[package]]
name = "rendy-memory"
version = "0.4.0"
source = "git+https://github.com/amethyst/rendy?rev=a8ac0de977a28d09592d615f8857461622833443#a8ac0de977a28d09592d615f8857461622833443"
source = "git+https://github.com/amethyst/rendy?rev=e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86#e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86"
dependencies = [
"colorful 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"hibitset 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"relevant 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -906,18 +906,18 @@ dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-dx11 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-backend-dx12 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-backend-empty 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-backend-metal 0.3.2 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-backend-vulkan 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)",
"gfx-backend-dx11 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"gfx-backend-dx12 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"gfx-backend-empty 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"gfx-backend-metal 0.3.2 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"gfx-backend-vulkan 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rendy-descriptor 0.4.0 (git+https://github.com/amethyst/rendy?rev=a8ac0de977a28d09592d615f8857461622833443)",
"rendy-memory 0.4.0 (git+https://github.com/amethyst/rendy?rev=a8ac0de977a28d09592d615f8857461622833443)",
"rendy-descriptor 0.4.0 (git+https://github.com/amethyst/rendy?rev=e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86)",
"rendy-memory 0.4.0 (git+https://github.com/amethyst/rendy?rev=e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86)",
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1023,12 +1023,12 @@ dependencies = [
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
"checksum gfx-backend-dx11 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)" = "<none>"
"checksum gfx-backend-dx12 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)" = "<none>"
"checksum gfx-backend-empty 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)" = "<none>"
"checksum gfx-backend-metal 0.3.2 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)" = "<none>"
"checksum gfx-backend-vulkan 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)" = "<none>"
"checksum gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)" = "<none>"
"checksum gfx-backend-dx11 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)" = "<none>"
"checksum gfx-backend-dx12 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)" = "<none>"
"checksum gfx-backend-empty 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)" = "<none>"
"checksum gfx-backend-metal 0.3.2 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)" = "<none>"
"checksum gfx-backend-vulkan 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)" = "<none>"
"checksum gfx-hal 0.3.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)" = "<none>"
"checksum hibitset 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47e7292fd9f7fe89fa35c98048f2d0a69b79ed243604234d18f6f8a1aa6f408d"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum ipc-channel 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79d98ee7dd1d2e796d254807fd86ea7189d07571aeaa74007603e29a79d15217"
@ -1061,14 +1061,14 @@ dependencies = [
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum range-alloc 0.1.0 (git+https://github.com/gfx-rs/gfx?rev=a084a1f2fec6c9ed928c53e2dc8c1761782b9019)" = "<none>"
"checksum range-alloc 0.1.0 (git+https://github.com/gfx-rs/gfx?rev=3d5db15661127c8cad8d85522a68ec36c82f6e69)" = "<none>"
"checksum raw-window-handle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "af3d3b2e1053b3ff2171efc29a8bff3439ce6b2ce6a0432695134bc1c7ff8e87"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum relevant 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bbc232e13d37f4547f5b9b42a5efc380cabe5dbc1807f8b893580640b2ab0308"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rendy-descriptor 0.4.0 (git+https://github.com/amethyst/rendy?rev=a8ac0de977a28d09592d615f8857461622833443)" = "<none>"
"checksum rendy-memory 0.4.0 (git+https://github.com/amethyst/rendy?rev=a8ac0de977a28d09592d615f8857461622833443)" = "<none>"
"checksum rendy-descriptor 0.4.0 (git+https://github.com/amethyst/rendy?rev=e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86)" = "<none>"
"checksum rendy-memory 0.4.0 (git+https://github.com/amethyst/rendy?rev=e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86)" = "<none>"
"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"

View File

@ -648,7 +648,6 @@ typedef struct {
} WGPURequestAdapterOptions;
typedef struct {
WGPUTextureId texture_id;
WGPUTextureViewId view_id;
} WGPUSwapChainOutput;
@ -900,7 +899,9 @@ void wgpu_render_pass_set_viewport(WGPURenderPassId pass_id,
WGPUAdapterId wgpu_request_adapter(const WGPURequestAdapterOptions *desc);
#endif
#if !defined(WGPU_REMOTE)
WGPUSwapChainOutput wgpu_swap_chain_get_next_texture(WGPUSwapChainId swap_chain_id);
#endif
void wgpu_swap_chain_present(WGPUSwapChainId swap_chain_id);

View File

@ -28,23 +28,23 @@ bitflags = "1.0"
copyless = "0.1"
lazy_static = "1.1.0"
log = "0.4"
hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "a084a1f2fec6c9ed928c53e2dc8c1761782b9019" }
gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "a084a1f2fec6c9ed928c53e2dc8c1761782b9019" }
hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "3d5db15661127c8cad8d85522a68ec36c82f6e69" }
gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "3d5db15661127c8cad8d85522a68ec36c82f6e69" }
parking_lot = "0.9"
raw-window-handle = "0.1"
rendy-memory = { git = "https://github.com/amethyst/rendy", rev = "a8ac0de977a28d09592d615f8857461622833443" }
rendy-descriptor = { git = "https://github.com/amethyst/rendy", rev = "a8ac0de977a28d09592d615f8857461622833443" }
rendy-memory = { git = "https://github.com/amethyst/rendy", rev = "e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86" }
rendy-descriptor = { git = "https://github.com/amethyst/rendy", rev = "e8ffcabc2bc74fbb282d4f71fa55c28d0ec31c86" }
serde = { version = "1.0", features = ["serde_derive"], optional = true }
vec_map = "0.8"
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
gfx-backend-metal = { git = "https://github.com/gfx-rs/gfx", rev = "a084a1f2fec6c9ed928c53e2dc8c1761782b9019" }
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "a084a1f2fec6c9ed928c53e2dc8c1761782b9019", optional = true }
gfx-backend-metal = { git = "https://github.com/gfx-rs/gfx", rev = "3d5db15661127c8cad8d85522a68ec36c82f6e69" }
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "3d5db15661127c8cad8d85522a68ec36c82f6e69", optional = true }
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "a084a1f2fec6c9ed928c53e2dc8c1761782b9019", features = ["x11"] }
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "3d5db15661127c8cad8d85522a68ec36c82f6e69", features = ["x11"] }
[target.'cfg(windows)'.dependencies]
gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "a084a1f2fec6c9ed928c53e2dc8c1761782b9019" }
gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "a084a1f2fec6c9ed928c53e2dc8c1761782b9019" }
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "a084a1f2fec6c9ed928c53e2dc8c1761782b9019" }
gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "3d5db15661127c8cad8d85522a68ec36c82f6e69" }
gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "3d5db15661127c8cad8d85522a68ec36c82f6e69" }
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "3d5db15661127c8cad8d85522a68ec36c82f6e69" }

View File

@ -87,7 +87,7 @@ impl<B: GfxBackend> CommandAllocator<B> {
device_id,
life_guard: LifeGuard::new(),
trackers: TrackerSet::new(B::VARIANT),
swap_chain_links: Vec::new(),
used_swap_chain_image: None,
}
}

View File

@ -21,8 +21,7 @@ use crate::{
gfx_select,
hub::{GfxBackend, Storage, Token},
id::{Input, Output},
resource::TexturePlacement,
swap_chain::{SwapChainLink, SwapImageEpoch},
resource::TextureViewInner,
track::{Stitch, TrackerSet},
Buffer,
BufferId,
@ -46,7 +45,15 @@ use log::trace;
#[cfg(not(feature = "remote"))]
use std::marker::PhantomData;
use std::{collections::hash_map::Entry, iter, mem, ptr, slice, thread::ThreadId};
use std::{
borrow::Borrow,
collections::hash_map::Entry,
iter,
mem,
ptr,
slice,
thread::ThreadId,
};
pub struct RenderBundle<B: hal::Backend> {
@ -111,7 +118,7 @@ pub struct CommandBuffer<B: hal::Backend> {
device_id: Stored<DeviceId>,
pub(crate) life_guard: LifeGuard,
pub(crate) trackers: TrackerSet,
pub(crate) swap_chain_links: Vec<SwapChainLink<SwapImageEpoch>>,
pub(crate) used_swap_chain_image: Option<Stored<TextureViewId>>,
}
impl<B: GfxBackend> CommandBuffer<B> {
@ -187,7 +194,13 @@ pub fn command_encoder_finish<B: GfxBackend>(
let mut token = Token::root();
//TODO: actually close the last recorded command buffer
let (mut comb_guard, _) = hub.command_buffers.write(&mut token);
comb_guard[encoder_id].is_recording = false; //TODO: check for the old value
let comb = &mut comb_guard[encoder_id];
assert!(comb.is_recording);
comb.is_recording = false;
// stop tracking the swapchain image, if used
if let Some(ref view_id) = comb.used_swap_chain_image {
comb.trackers.views.remove(view_id.value);
}
encoder_id
}
@ -255,7 +268,6 @@ pub fn command_encoder_begin_render_pass<B: GfxBackend>(
);
let rp_key = {
let trackers = &mut cmb.trackers;
let swap_chain_links = &mut cmb.swap_chain_links;
let depth_stencil = depth_stencil_attachment.map(|at| {
let view = trackers
@ -267,13 +279,18 @@ pub fn command_encoder_begin_render_pass<B: GfxBackend>(
} else {
extent = Some(view.extent);
}
let texture_id = match view.inner {
TextureViewInner::Native { ref source_id, .. } => source_id.value,
TextureViewInner::SwapChain {..} =>
panic!("Unexpected depth/stencil use of swapchain image!"),
};
let texture = &texture_guard[view.texture_id.value];
let texture = &texture_guard[texture_id];
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let old_layout = match trackers
.textures
.query(view.texture_id.value, view.range.clone())
.query(texture_id, view.range.clone())
{
Some(usage) => {
conv::map_texture_state(
@ -286,7 +303,7 @@ pub fn command_encoder_begin_render_pass<B: GfxBackend>(
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let pending = trackers.textures.change_replace(
view.texture_id.value,
texture_id,
&texture.life_guard.ref_count,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
@ -317,10 +334,7 @@ pub fn command_encoder_begin_render_pass<B: GfxBackend>(
let mut resolves = ArrayVec::new();
for at in color_attachments {
let view = trackers
.views
.use_extend(&*view_guard, at.attachment, (), ())
.unwrap();
let view = &view_guard[at.attachment];
if let Some(ex) = extent {
assert_eq!(ex, view.extent);
} else {
@ -330,47 +344,55 @@ pub fn command_encoder_begin_render_pass<B: GfxBackend>(
view.samples, sample_count,
"All attachments must have the same sample_count"
);
let first_use = trackers.views
.init(at.attachment, &view.life_guard.ref_count, (), ());
if view.is_owned_by_swap_chain {
let link = match texture_guard[view.texture_id.value].placement {
TexturePlacement::SwapChain(ref link) => SwapChainLink {
swap_chain_id: link.swap_chain_id.clone(),
epoch: *link.epoch.lock(),
image_index: link.image_index,
},
TexturePlacement::Memory(_) => unreachable!(),
};
swap_chain_links.push(link);
}
let layouts = match view.inner {
TextureViewInner::Native { ref source_id, .. } => {
let texture = &texture_guard[source_id.value];
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let texture = &texture_guard[view.texture_id.value];
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let old_layout = match trackers
.textures
.query(view.texture_id.value, view.range.clone())
{
Some(usage) => conv::map_texture_state(usage, hal::format::Aspects::COLOR).1,
None => {
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let pending = trackers.textures.change_replace(
view.texture_id.value,
&texture.life_guard.ref_count,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
);
barriers.extend(pending.map(|pending| {
trace!("\tcolor {:?}", pending);
hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture.raw,
families: None,
range: pending.selector,
let old_layout = match trackers
.textures
.query(source_id.value, view.range.clone())
{
Some(usage) => conv::map_texture_state(usage, hal::format::Aspects::COLOR).1,
None => {
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let pending = trackers.textures.change_replace(
source_id.value,
&texture.life_guard.ref_count,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
);
barriers.extend(pending.map(|pending| {
trace!("\tcolor {:?}", pending);
hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture.raw,
families: None,
range: pending.selector,
}
}));
hal::image::Layout::ColorAttachmentOptimal
}
}));
hal::image::Layout::ColorAttachmentOptimal
};
old_layout .. hal::image::Layout::ColorAttachmentOptimal
}
TextureViewInner::SwapChain { .. } => {
if let Some(ref view_id) = cmb.used_swap_chain_image {
assert_eq!(view_id.value, at.attachment);
} else {
cmb.used_swap_chain_image = Some(Stored {
value: at.attachment,
ref_count: view.life_guard.ref_count.clone(),
});
}
let end = hal::image::Layout::Present;
let start = if first_use { hal::image::Layout::Undefined } else { end };
start .. end
}
};
@ -379,80 +401,82 @@ pub fn command_encoder_begin_render_pass<B: GfxBackend>(
samples: view.samples,
ops: conv::map_load_store_ops(at.load_op, at.store_op),
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts: old_layout .. hal::image::Layout::ColorAttachmentOptimal,
layouts,
});
}
if let Some(resolve_target) = unsafe { at.resolve_target.as_ref() } {
let view = trackers
.views
.use_extend(&*view_guard, *resolve_target, (), ())
.unwrap();
if let Some(ex) = extent {
assert_eq!(ex, view.extent);
} else {
extent = Some(view.extent);
}
assert_eq!(
view.samples, 1,
"All resolve_targets must have a sample_count of 1"
);
for &resolve_target in color_attachments
.iter()
.flat_map(|at| unsafe { at.resolve_target.as_ref() })
{
let view = &view_guard[resolve_target];
assert_eq!(extent, Some(view.extent));
assert_eq!(
view.samples, 1,
"All resolve_targets must have a sample_count of 1"
);
let first_use = trackers.views
.init(resolve_target, &view.life_guard.ref_count, (), ());
if view.is_owned_by_swap_chain {
let link = match texture_guard[view.texture_id.value].placement {
TexturePlacement::SwapChain(ref link) => SwapChainLink {
swap_chain_id: link.swap_chain_id.clone(),
epoch: *link.epoch.lock(),
image_index: link.image_index,
},
TexturePlacement::Memory(_) => unreachable!(),
let layouts = match view.inner {
TextureViewInner::Native { ref source_id, .. } => {
let texture = &texture_guard[source_id.value];
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let old_layout = match trackers
.textures
.query(source_id.value, view.range.clone())
{
Some(usage) => conv::map_texture_state(usage, hal::format::Aspects::COLOR).1,
None => {
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let pending = trackers.textures.change_replace(
source_id.value,
&texture.life_guard.ref_count,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
);
barriers.extend(pending.map(|pending| {
trace!("\tresolve {:?}", pending);
hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture.raw,
families: None,
range: pending.selector,
}
}));
hal::image::Layout::ColorAttachmentOptimal
}
};
swap_chain_links.push(link);
old_layout .. hal::image::Layout::ColorAttachmentOptimal
}
let texture = &texture_guard[view.texture_id.value];
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let old_layout = match trackers
.textures
.query(view.texture_id.value, view.range.clone())
{
Some(usage) => {
conv::map_texture_state(usage, hal::format::Aspects::COLOR).1
TextureViewInner::SwapChain { .. } => {
if let Some(ref view_id) = cmb.used_swap_chain_image {
assert_eq!(view_id.value, resolve_target);
} else {
cmb.used_swap_chain_image = Some(Stored {
value: resolve_target,
ref_count: view.life_guard.ref_count.clone(),
});
}
None => {
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let pending = trackers.textures.change_replace(
view.texture_id.value,
&texture.life_guard.ref_count,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
);
barriers.extend(pending.map(|pending| {
trace!("\tresolve {:?}", pending);
hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture.raw,
families: None,
range: pending.selector,
}
}));
hal::image::Layout::ColorAttachmentOptimal
}
};
let end = hal::image::Layout::Present;
let start = if first_use { hal::image::Layout::Undefined } else { end };
start .. end
}
};
resolves.push(hal::pass::Attachment {
format: Some(conv::map_texture_format(view.format)),
samples: view.samples,
ops: hal::pass::AttachmentOps::new(
hal::pass::AttachmentLoadOp::DontCare,
hal::pass::AttachmentStoreOp::Store,
),
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts: old_layout .. hal::image::Layout::ColorAttachmentOptimal,
});
}
resolves.push(hal::pass::Attachment {
format: Some(conv::map_texture_format(view.format)),
samples: view.samples,
ops: hal::pass::AttachmentOps::new(
hal::pass::AttachmentLoadOp::DontCare,
hal::pass::AttachmentStoreOp::Store,
),
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts,
});
}
RenderPassKey {
@ -544,8 +568,10 @@ pub fn command_encoder_begin_render_pass<B: GfxBackend>(
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
let fb = {
let attachments = e.key().all().map(|&id| &view_guard[id].raw);
let attachments = e.key().all().map(|&id| match view_guard[id].inner {
TextureViewInner::Native { ref raw, .. } => raw,
TextureViewInner::SwapChain { ref image, .. } => Borrow::borrow(image),
});
unsafe {
device
.raw

View File

@ -3,8 +3,6 @@ use crate::{
device::{all_buffer_stages, all_image_stages},
gfx_select,
hub::{GfxBackend, Token},
resource::TexturePlacement,
swap_chain::SwapChainLink,
BufferAddress,
BufferId,
BufferUsage,
@ -15,7 +13,6 @@ use crate::{
TextureUsage,
};
use copyless::VecHelper as _;
use hal::command::CommandBuffer as _;
use std::iter;
@ -183,14 +180,6 @@ pub fn command_encoder_copy_buffer_to_texture<B: GfxBackend>(
range: pending.selector,
});
if let TexturePlacement::SwapChain(ref link) = dst_texture.placement {
cmb.swap_chain_links.alloc().init(SwapChainLink {
swap_chain_id: link.swap_chain_id.clone(),
epoch: *link.epoch.lock(),
image_index: link.image_index,
});
}
let aspects = dst_texture.full_range.aspects;
let bytes_per_texel = conv::map_texture_format(dst_texture.format)
.surface_desc()
@ -265,10 +254,6 @@ pub fn command_encoder_copy_texture_to_buffer<B: GfxBackend>(
families: None,
range: pending.selector,
});
match src_texture.placement {
TexturePlacement::SwapChain(_) => unimplemented!(),
TexturePlacement::Memory(_) => (),
}
let (dst_buffer, dst_barriers) = cmb.trackers.buffers.use_replace(
&*buffer_guard,
@ -380,14 +365,6 @@ pub fn command_encoder_copy_texture_to_texture<B: GfxBackend>(
range: pending.selector,
}));
if let TexturePlacement::SwapChain(ref link) = dst_texture.placement {
cmb.swap_chain_links.alloc().init(SwapChainLink {
swap_chain_id: link.swap_chain_id.clone(),
epoch: *link.epoch.lock(),
image_index: link.image_index,
});
}
let aspects = src_texture.full_range.aspects & dst_texture.full_range.aspects;
let region = hal::command::ImageCopy {
src_subresource: source.to_sub_layers(aspects),

View File

@ -1,5 +1,7 @@
#[cfg(not(feature = "remote"))]
use crate::instance::Limits;
use crate::{
instance::Limits,
};
use crate::{
binding_model,
command,
@ -45,11 +47,9 @@ use hal::{
backend::FastHashMap,
command::CommandBuffer as _,
device::Device as _,
pool::CommandPool as _,
queue::CommandQueue as _,
window::Surface as _,
window::{PresentationSurface as _, Surface as _},
};
use log::{info, trace};
use parking_lot::Mutex;
use rendy_descriptor::{DescriptorAllocator, DescriptorRanges, DescriptorSet};
use rendy_memory::{Block, Heaps, MemoryBlock};
@ -63,7 +63,7 @@ use std::{
ops::Range,
ptr,
slice,
sync::atomic::{AtomicBool, Ordering},
sync::atomic::{Ordering},
};
@ -228,7 +228,7 @@ impl<B: GfxBackend> PendingResources<B> {
};
for a in self.active.drain(.. done_count) {
trace!("Active submission {} is done", a.index);
log::trace!("Active submission {} is done", a.index);
self.free.extend(a.resources.into_iter().map(|(_, r)| r));
self.ready_to_map.extend(a.mapped);
unsafe {
@ -296,33 +296,32 @@ impl<B: GfxBackend> PendingResources<B> {
continue;
}
trackers.buffers.remove(id);
let buf = buffer_guard.remove(id);
let buf = buffer_guard.remove(id).unwrap();
#[cfg(not(feature = "remote"))]
hub.buffers.identity.lock().free(id);
(buf.life_guard, NativeResource::Buffer(buf.raw, buf.memory))
}
ResourceId::Texture(id) => {
trackers.textures.remove(id);
let tex = texture_guard.remove(id);
let tex = texture_guard.remove(id).unwrap();
#[cfg(not(feature = "remote"))]
hub.textures.identity.lock().free(id);
let memory = match tex.placement {
// swapchain-owned images don't need explicit destruction
resource::TexturePlacement::SwapChain(_) => continue,
resource::TexturePlacement::Memory(mem) => mem,
};
(tex.life_guard, NativeResource::Image(tex.raw, memory))
(tex.life_guard, NativeResource::Image(tex.raw, tex.memory))
}
ResourceId::TextureView(id) => {
trackers.views.remove(id);
let view = teview_view_guard.remove(id);
let view = teview_view_guard.remove(id).unwrap();
let raw = match view.inner {
resource::TextureViewInner::Native { raw, .. } => raw,
resource::TextureViewInner::SwapChain { .. } => unreachable!(),
};
#[cfg(not(feature = "remote"))]
hub.texture_views.identity.lock().free(id);
(view.life_guard, NativeResource::ImageView(view.raw))
(view.life_guard, NativeResource::ImageView(raw))
}
ResourceId::BindGroup(id) => {
trackers.bind_groups.remove(id);
let bind_group = bind_group_guard.remove(id);
let bind_group = bind_group_guard.remove(id).unwrap();
#[cfg(not(feature = "remote"))]
hub.bind_groups.identity.lock().free(id);
(
@ -354,7 +353,7 @@ impl<B: GfxBackend> PendingResources<B> {
let buf = &buffer_guard[resource_id];
let submit_index = buf.life_guard.submission_index.load(Ordering::Acquire);
trace!(
log::trace!(
"Mapping of {:?} at submission {:?} gets assigned to active {:?}",
resource_id,
submit_index,
@ -714,7 +713,7 @@ impl<B: GfxBackend> Device<B> {
levels: 0 .. desc.mip_level_count as hal::image::Level,
layers: 0 .. desc.array_layer_count as hal::image::Layer,
},
placement: resource::TexturePlacement::Memory(memory),
memory,
life_guard: LifeGuard::new(),
}
}
@ -929,16 +928,17 @@ pub fn texture_create_view<B: GfxBackend>(
};
let view = resource::TextureView {
raw,
texture_id: Stored {
value: texture_id,
ref_count: texture.life_guard.ref_count.clone(),
inner: resource::TextureViewInner::Native {
raw,
source_id: Stored {
value: texture_id,
ref_count: texture.life_guard.ref_count.clone(),
},
},
format: texture.format,
extent: texture.kind.extent().at_level(range.levels.start),
samples: texture.kind.num_samples(),
range,
is_owned_by_swap_chain: false,
life_guard: LifeGuard::new(),
};
@ -991,7 +991,12 @@ pub fn texture_view_destroy<B: GfxBackend>(texture_view_id: TextureViewId) {
let (texture_guard, mut token) = hub.textures.read(&mut token);
let (texture_view_guard, _) = hub.texture_views.read(&mut token);
let view = &texture_view_guard[texture_view_id];
let device_id = texture_guard[view.texture_id.value].device_id.value;
let device_id = match view.inner {
resource::TextureViewInner::Native { ref source_id, .. } =>
texture_guard[source_id.value].device_id.value,
resource::TextureViewInner::SwapChain { .. } =>
panic!("Can't destroy a swap chain image"),
};
device_guard[device_id].pending.lock().destroy(
ResourceId::TextureView(texture_view_id),
view.life_guard.ref_count.clone(),
@ -1248,17 +1253,23 @@ pub fn device_create_bind_group<B: GfxBackend>(
.views
.use_extend(&*texture_view_guard, id, (), ())
.unwrap();
let texture = used.textures
.use_extend(
&*texture_guard,
view.texture_id.value,
view.range.clone(),
usage,
)
.unwrap();
assert!(texture.usage.contains(usage));
match view.inner {
resource::TextureViewInner::Native { ref raw, ref source_id } => {
let texture = used.textures
.use_extend(
&*texture_guard,
source_id.value,
view.range.clone(),
usage,
)
.unwrap();
assert!(texture.usage.contains(usage));
hal::pso::Descriptor::Image(&view.raw, image_layout)
hal::pso::Descriptor::Image(raw, image_layout)
}
resource::TextureViewInner::SwapChain { .. } =>
panic!("Unable to create a bind group with a swap chain image"),
}
}
};
writes.alloc().init(hal::pso::DescriptorSetWrite {
@ -1409,117 +1420,108 @@ pub fn queue_submit<B: GfxBackend>(queue_id: QueueId, command_buffer_ids: &[Comm
let (mut device_guard, mut token) = hub.devices.write(&mut token);
let (swap_chain_guard, mut token) = hub.swap_chains.read(&mut token);
let device = &mut device_guard[queue_id];
let mut trackers = device.trackers.lock();
let mut wait_semaphores = Vec::new();
let mut signal_semaphores = Vec::new();
let submit_index = 1 + device
.life_guard
.submission_index
.fetch_add(1, Ordering::Relaxed);
let (mut command_buffer_guard, mut token) = hub.command_buffers.write(&mut token);
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
let (texture_guard, mut token) = hub.textures.read(&mut token);
let (texture_view_guard, _) = hub.texture_views.read(&mut token);
//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.
{
let (mut command_buffer_guard, mut token) = hub.command_buffers.write(&mut token);
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
let (texture_guard, mut token) = hub.textures.read(&mut token);
let (texture_view_guard, _) = hub.texture_views.read(&mut token);
// finish all the command buffers first
for &cmb_id in command_buffer_ids {
let comb = &mut command_buffer_guard[cmb_id];
for link in comb.swap_chain_links.drain(..) {
let swap_chain = &swap_chain_guard[link.swap_chain_id];
let frame = &swap_chain.frames[link.image_index as usize];
if frame.need_waiting.swap(false, Ordering::AcqRel) {
assert_eq!(frame.acquired_epoch, Some(link.epoch),
"{}. Image index {} with epoch {} != current epoch {:?}",
"Attempting to render to a swapchain output that has already been presented",
link.image_index, link.epoch, frame.acquired_epoch);
wait_semaphores.push((
&frame.sem_available,
hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
));
}
}
// finish all the command buffers first
for &cmb_id in command_buffer_ids {
let comb = &mut command_buffer_guard[cmb_id];
// optimize the tracked states
comb.trackers.optimize();
if let Some(view_id) = comb.used_swap_chain_image.take() {
let sem = match texture_view_guard[view_id.value].inner {
resource::TextureViewInner::Native { .. } => unreachable!(),
resource::TextureViewInner::SwapChain { ref source_id, .. } =>
&swap_chain_guard[source_id.value].semaphore,
};
signal_semaphores.push(sem);
}
// update submission IDs
for id in comb.trackers.buffers.used() {
let buffer = &buffer_guard[id];
assert!(buffer.pending_map_operation.is_none());
buffer
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
}
for id in comb.trackers.textures.used() {
texture_guard[id]
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
}
for id in comb.trackers.views.used() {
texture_view_guard[id]
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
}
for id in comb.trackers.bind_groups.used() {
bind_group_guard[id]
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
}
// optimize the tracked states
comb.trackers.optimize();
// execute resource transitions
let mut transit = device.com_allocator.extend(comb);
unsafe {
transit.begin(
hal::command::CommandBufferFlags::ONE_TIME_SUBMIT,
hal::command::CommandBufferInheritanceInfo::default(),
);
}
trace!("Stitching command buffer {:?} before submission", cmb_id);
command::CommandBuffer::insert_barriers(
&mut transit,
&mut *trackers,
&comb.trackers,
Stitch::Init,
&*buffer_guard,
&*texture_guard,
// update submission IDs
for id in comb.trackers.buffers.used() {
let buffer = &buffer_guard[id];
assert!(buffer.pending_map_operation.is_none());
buffer
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
}
for id in comb.trackers.textures.used() {
texture_guard[id]
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
}
for id in comb.trackers.views.used() {
texture_view_guard[id]
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
}
for id in comb.trackers.bind_groups.used() {
bind_group_guard[id]
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
}
// execute resource transitions
let mut transit = device.com_allocator.extend(comb);
unsafe {
transit.begin(
hal::command::CommandBufferFlags::ONE_TIME_SUBMIT,
hal::command::CommandBufferInheritanceInfo::default(),
);
unsafe {
transit.finish();
}
comb.raw.insert(0, transit);
unsafe {
comb.raw.last_mut().unwrap().finish();
}
}
log::trace!("Stitching command buffer {:?} before submission", cmb_id);
command::CommandBuffer::insert_barriers(
&mut transit,
&mut *trackers,
&comb.trackers,
Stitch::Init,
&*buffer_guard,
&*texture_guard,
);
unsafe {
transit.finish();
}
comb.raw.insert(0, transit);
unsafe {
comb.raw.last_mut().unwrap().finish();
}
}
// now prepare the GPU submission
let fence = device.raw.create_fence(false).unwrap();
{
let (command_buffer_guard, _) = hub.command_buffers.read(&mut token);
let submission = hal::queue::Submission::<_, _, &[B::Semaphore]> {
//TODO: may `OneShot` be enough?
command_buffers: command_buffer_ids
.iter()
.flat_map(|&cmb_id| &command_buffer_guard[cmb_id].raw),
wait_semaphores,
signal_semaphores: &[], //TODO: signal `sem_present`?
};
let submission = hal::queue::Submission::<_, _, Vec<&B::Semaphore>> {
command_buffers: command_buffer_ids
.iter()
.flat_map(|&cmb_id| &command_buffer_guard[cmb_id].raw),
wait_semaphores: Vec::new(),
signal_semaphores,
};
unsafe {
device.queue_group.queues[0]
.submit(submission, Some(&fence));
}
unsafe {
device.queue_group.queues[0]
.submit(submission, Some(&fence));
}
(submit_index, fence)
@ -1896,16 +1898,15 @@ pub fn device_create_swap_chain<B: GfxBackend>(
device_id: DeviceId,
surface_id: SurfaceId,
desc: &swap_chain::SwapChainDescriptor,
id_in: Input<SwapChainId>,
image_ids: Vec<(Input<TextureId>, Input<TextureViewId>)>,
) -> Output<SwapChainId> {
info!("creating swap chain {:?}", desc);
) -> SwapChainId {
log::info!("creating swap chain {:?}", desc);
let hub = B::hub();
let mut token = Token::root();
let (mut surface_guard, mut token) = GLOBAL.surfaces.write(&mut token);
let (adapter_guard, mut token) = hub.adapters.read(&mut token);
let (device_guard, mut token) = hub.devices.read(&mut token);
let (mut swap_chain_guard, _) = hub.swap_chains.write(&mut token);
let device = &device_guard[device_id];
let surface = &mut surface_guard[surface_id];
@ -1926,159 +1927,41 @@ pub fn device_create_swap_chain<B: GfxBackend>(
formats
);
}
//TODO: properly exclusive range
/* TODO: this is way too restrictive
assert!(desc.width >= caps.extents.start.width && desc.width <= caps.extents.end.width &&
desc.height >= caps.extents.start.height && desc.height <= caps.extents.end.height,
"Requested size {}x{} is outside of the supported range: {:?}",
desc.width, desc.height, caps.extents);
*/
if desc.width < caps.extents.start().width ||
desc.width > caps.extents.end().width ||
desc.height < caps.extents.start().height ||
desc.height > caps.extents.end().height
{
log::warn!("Requested size {}x{} is outside of the supported range: {:?}",
desc.width, desc.height, caps.extents);
}
let (old_raw, sem_available, command_pool) = match surface.swap_chain.take() {
Some(old_id) => {
//TODO: remove this once gfx-rs stops destroying the old swapchain
device.raw.wait_idle().unwrap();
let mut pending = device.pending.lock();
let hal_desc = desc.to_hal(num_frames);
unsafe {
B::get_surface_mut(surface)
.configure_swapchain(&device.raw, hal_desc)
.unwrap();
}
let (mut old, _) = hub.swap_chains.unregister(old_id, &mut token);
assert_eq!(old.device_id.value, device_id);
for frame in old.frames {
pending.destroy(
ResourceId::Texture(frame.texture_id.value),
frame.texture_id.ref_count,
);
pending.destroy(
ResourceId::TextureView(frame.view_id.value),
frame.view_id.ref_count,
);
}
unsafe { old.command_pool.reset(false) };
(old.raw, old.sem_available, old.command_pool)
let sc_id = surface_id.to_swap_chain_id(B::VARIANT);
if let Some(sc) = swap_chain_guard.remove(sc_id) {
unsafe {
device.raw.destroy_semaphore(sc.semaphore);
}
None => unsafe {
let sem_available = device.raw.create_semaphore().unwrap();
let command_pool = device
.raw
.create_command_pool(
device.queue_group.family,
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
)
.unwrap();
(None, sem_available, command_pool)
},
};
let (raw_swap_chain, images) = unsafe {
let suf = B::get_surface_mut(surface);
device
.raw
.create_swapchain(suf, config, old_raw)
.unwrap()
};
let (id, id_out) = hub.swap_chains.new_identity(id_in);
surface.swap_chain = Some(id);
let mut trackers = device.trackers.lock();
let mut swap_chain = swap_chain::SwapChain::<B> {
raw: Some(raw_swap_chain),
surface_id: Stored {
value: surface_id,
ref_count: surface.ref_count.clone(),
},
}
let swap_chain = swap_chain::SwapChain {
life_guard: LifeGuard::new(),
device_id: Stored {
value: device_id,
ref_count: device.life_guard.ref_count.clone(),
},
desc: desc.clone(),
frames: Vec::with_capacity(num_frames as usize),
acquired: Vec::with_capacity(1), //TODO: get it from gfx-hal?
sem_available,
command_pool,
num_frames,
acquired_view_id: None,
semaphore: device.raw.create_semaphore().unwrap(),
};
for ((i, image), (id_texture_in, id_view_in)) in images.into_iter().enumerate().zip(image_ids) {
let kind = hal::image::Kind::D2(desc.width, desc.height, 1, 1);
let range = hal::image::SubresourceRange {
aspects: hal::format::Aspects::COLOR,
levels: 0 .. 1,
layers: 0 .. 1,
};
let view_raw = unsafe {
device
.raw
.create_image_view(
&image,
hal::image::ViewKind::D2,
conv::map_texture_format(desc.format),
hal::format::Swizzle::NO,
range.clone(),
)
.unwrap()
};
let texture = resource::Texture {
raw: image,
device_id: Stored {
value: device_id,
ref_count: device.life_guard.ref_count.clone(),
},
usage: resource::TextureUsage::OUTPUT_ATTACHMENT,
kind,
format: desc.format,
full_range: range.clone(),
placement: resource::TexturePlacement::SwapChain(swap_chain::SwapChainLink {
swap_chain_id: id, //TODO: strongly
epoch: Mutex::new(0),
image_index: i as hal::window::SwapImageIndex,
}),
life_guard: LifeGuard::new(),
};
let (id_texture, _) = hub.textures.new_identity(id_texture_in);
let texture_id = Stored {
ref_count: texture.life_guard.ref_count.clone(),
value: id_texture,
};
trackers.textures.init(
id_texture,
&texture_id.ref_count,
range.clone(),
resource::TextureUsage::UNINITIALIZED,
);
hub.textures.register(id_texture, texture, &mut token);
let view = resource::TextureView {
raw: view_raw,
texture_id: texture_id.clone(),
format: desc.format,
extent: kind.extent(),
samples: kind.num_samples(),
range,
is_owned_by_swap_chain: true,
life_guard: LifeGuard::new(),
};
let (id_view, _) = hub.texture_views.new_identity(id_view_in);
let view_id = Stored {
ref_count: view.life_guard.ref_count.clone(),
value: id_view,
};
trackers.views.init(id_view, &view_id.ref_count, (), ());
hub.texture_views.register(id_view, view, &mut token);
swap_chain.frames.alloc().init(swap_chain::Frame {
texture_id,
view_id,
fence: device.raw.create_fence(true).unwrap(),
sem_available: device.raw.create_semaphore().unwrap(),
sem_present: device.raw.create_semaphore().unwrap(),
acquired_epoch: None,
need_waiting: AtomicBool::new(false),
comb: swap_chain.command_pool.allocate_one(hal::command::Level::Primary),
});
}
hub.swap_chains.register(id, swap_chain, &mut token);
id_out
swap_chain_guard.insert(sc_id, swap_chain);
sc_id
}
#[cfg(not(feature = "remote"))]
@ -2088,8 +1971,7 @@ pub extern "C" fn wgpu_device_create_swap_chain(
surface_id: SurfaceId,
desc: &swap_chain::SwapChainDescriptor,
) -> SwapChainId {
let image_ids = vec![(PhantomData, PhantomData); 10]; //TODO: make this compatible with "remote"
gfx_select!(device_id => device_create_swap_chain(device_id, surface_id, desc, PhantomData, image_ids))
gfx_select!(device_id => device_create_swap_chain(device_id, surface_id, desc))
}
pub fn device_poll<B: GfxBackend>(device_id: DeviceId, force_wait: bool) {

View File

@ -135,11 +135,19 @@ impl<T, I: TypedId> Storage<T, I> {
}
}
pub fn remove(&mut self, id: I) -> T {
pub fn insert(&mut self, id: I, value: T) -> Option<T> {
let (index, epoch, _) = id.unzip();
let (value, storage_epoch) = self.map.remove(index as usize).unwrap();
assert_eq!(epoch, storage_epoch);
value
let old = self.map.insert(index as usize, (value, epoch));
old.map(|(v, _storage_epoch)| v)
}
pub fn remove(&mut self, id: I) -> Option<T> {
let (index, epoch, _) = id.unzip();
self.map.remove(index as usize)
.map(|(value, storage_epoch)| {
assert_eq!(epoch, storage_epoch);
value
})
}
}
@ -200,9 +208,9 @@ impl<B: hal::Backend> Access<Buffer<B>> for RenderPass<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for RenderPipeline<B> {}
impl<B: hal::Backend> Access<Texture<B>> for Root {}
impl<B: hal::Backend> Access<Texture<B>> for Device<B> {}
impl<B: hal::Backend> Access<Texture<B>> for SwapChain<B> {}
impl<B: hal::Backend> Access<Texture<B>> for Buffer<B> {}
impl<B: hal::Backend> Access<TextureView<B>> for Root {}
impl<B: hal::Backend> Access<TextureView<B>> for SwapChain<B> {}
impl<B: hal::Backend> Access<TextureView<B>> for Device<B> {}
impl<B: hal::Backend> Access<TextureView<B>> for Texture<B> {}
impl<B: hal::Backend> Access<Sampler<B>> for Root {}
@ -281,9 +289,8 @@ impl<T, I: TypedId> Registry<T, I> {
impl<T, I: TypedId + Copy> Registry<T, I> {
pub fn register<A: Access<T>>(&self, id: I, value: T, _token: &mut Token<A>) {
let (index, epoch, backend) = id.unzip();
debug_assert_eq!(backend, self.backend);
let old = self.data.write().map.insert(index as usize, (value, epoch));
debug_assert_eq!(id.unzip().2, self.backend);
let old = self.data.write().insert(id, value);
assert!(old.is_none());
}
@ -311,7 +318,7 @@ impl<T, I: TypedId + Copy> Registry<T, I> {
}
pub fn unregister<A: Access<T>>(&self, id: I, _token: &mut Token<A>) -> (T, Token<T>) {
let value = self.data.write().remove(id);
let value = self.data.write().remove(id).unwrap();
//Note: careful about the order here!
#[cfg(not(feature = "remote"))]
self.identity.lock().free(id);

View File

@ -35,7 +35,7 @@ impl<T> Clone for Id<T> {
impl<T> fmt::Debug for Id<T> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(formatter)
self.unzip().fmt(formatter)
}
}
@ -109,6 +109,19 @@ pub type ComputePassId = Id<crate::ComputePass<Dummy>>;
pub type SurfaceId = Id<crate::Surface>;
pub type SwapChainId = Id<crate::SwapChain<Dummy>>;
impl SurfaceId {
pub(crate) fn to_swap_chain_id(&self, backend: Backend) -> SwapChainId {
let (index, epoch, _) = self.unzip();
Id::zip(index, epoch, backend)
}
}
impl SwapChainId {
pub(crate) fn to_surface_id(&self) -> SurfaceId {
let (index, epoch, _) = self.unzip();
Id::zip(index, epoch, Backend::Empty)
}
}
#[test]
fn test_id_backend() {
for &b in &[

View File

@ -8,11 +8,9 @@ use crate::{
Backend,
Device,
DeviceId,
RefCount,
SwapChainId,
};
#[cfg(not(feature = "remote"))]
use crate::{gfx_select, LifeGuard, SurfaceId};
use crate::{gfx_select, SurfaceId};
#[cfg(not(feature = "remote"))]
use bitflags::bitflags;
@ -61,8 +59,6 @@ type GfxSurface<B> = <B as hal::Backend>::Surface;
#[derive(Debug)]
pub struct Surface {
pub(crate) swap_chain: Option<SwapChainId>,
pub(crate) ref_count: RefCount,
#[cfg(any(not(any(target_os = "ios", target_os = "macos")), feature = "gfx-backend-vulkan"))]
pub(crate) vulkan: Option<GfxSurface<backend::Vulkan>>,
#[cfg(any(target_os = "ios", target_os = "macos"))]
@ -163,12 +159,9 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
use raw_window_handle::RawWindowHandle as Rwh;
let instance = &GLOBAL.instance;
let ref_count = LifeGuard::new().ref_count;
let surface = match raw_handle {
#[cfg(target_os = "ios")]
Rwh::IOS(h) => Surface {
swap_chain: None,
ref_count,
#[cfg(feature = "gfx-backend-vulkan")]
vulkan: None,
metal: instance
@ -177,8 +170,6 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
},
#[cfg(target_os = "macos")]
Rwh::MacOS(h) => Surface {
swap_chain: None,
ref_count,
#[cfg(feature = "gfx-backend-vulkan")]
vulkan: instance
.vulkan
@ -190,8 +181,6 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
},
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
Rwh::X11(h) => Surface {
swap_chain: None,
ref_count,
vulkan: instance
.vulkan
.as_ref()
@ -199,8 +188,6 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
},
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
Rwh::Wayland(h) => Surface {
swap_chain: None,
ref_count,
vulkan: instance
.vulkan
.as_ref()
@ -208,8 +195,6 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
},
#[cfg(windows)]
Rwh::Windows(h) => Surface {
swap_chain: None,
ref_count,
vulkan: instance
.vulkan
.as_ref()
@ -247,8 +232,6 @@ pub extern "C" fn wgpu_create_surface_from_xlib(
#[no_mangle]
pub extern "C" fn wgpu_create_surface_from_metal_layer(layer: *mut std::ffi::c_void) -> SurfaceId {
let surface = Surface {
swap_chain: None,
ref_count: LifeGuard::new().ref_count,
#[cfg(feature = "gfx-backend-vulkan")]
vulkan: None, //TODO: currently requires `NSView`
metal: GLOBAL

View File

@ -1,5 +1,4 @@
use crate::{
swap_chain::{SwapChainLink, SwapImageEpoch},
BufferAddress,
BufferMapReadCallback,
BufferMapWriteCallback,
@ -8,12 +7,12 @@ use crate::{
LifeGuard,
RefCount,
Stored,
SwapChainId,
TextureId,
};
use bitflags::bitflags;
use hal;
use parking_lot::Mutex;
use rendy_memory::MemoryBlock;
use std::borrow::Borrow;
@ -207,22 +206,6 @@ pub struct TextureDescriptor {
pub usage: TextureUsage,
}
#[derive(Debug)]
pub(crate) enum TexturePlacement<B: hal::Backend> {
#[cfg_attr(not(not(feature = "remote")), allow(unused))]
SwapChain(SwapChainLink<Mutex<SwapImageEpoch>>),
Memory(MemoryBlock<B>),
}
impl<B: hal::Backend> TexturePlacement<B> {
pub fn as_swap_chain(&self) -> &SwapChainLink<Mutex<SwapImageEpoch>> {
match *self {
TexturePlacement::SwapChain(ref link) => link,
TexturePlacement::Memory(_) => panic!("Expected swap chain link!"),
}
}
}
#[derive(Debug)]
pub struct Texture<B: hal::Backend> {
pub(crate) raw: B::Image,
@ -231,7 +214,7 @@ pub struct Texture<B: hal::Backend> {
pub(crate) kind: hal::image::Kind,
pub(crate) format: TextureFormat,
pub(crate) full_range: hal::image::SubresourceRange,
pub(crate) placement: TexturePlacement<B>,
pub(crate) memory: MemoryBlock<B>,
pub(crate) life_guard: LifeGuard,
}
@ -278,17 +261,27 @@ pub struct TextureViewDescriptor {
pub array_layer_count: u32,
}
#[derive(Debug)]
pub(crate) enum TextureViewInner<B: hal::Backend> {
Native {
raw: B::ImageView,
source_id: Stored<TextureId>,
},
SwapChain {
image: <B::Surface as hal::window::PresentationSurface<B>>::SwapchainImage,
source_id: Stored<SwapChainId>,
},
}
#[derive(Debug)]
pub struct TextureView<B: hal::Backend> {
pub(crate) raw: B::ImageView,
pub(crate) texture_id: Stored<TextureId>,
pub(crate) inner: TextureViewInner<B>,
//TODO: store device_id for quick access?
pub(crate) format: TextureFormat,
pub(crate) extent: hal::image::Extent,
pub(crate) samples: hal::image::NumSamples,
pub(crate) range: hal::image::SubresourceRange,
pub(crate) is_owned_by_swap_chain: bool,
#[cfg_attr(not(not(feature = "remote")), allow(dead_code))]
#[cfg_attr(feature = "remote", allow(dead_code))]
pub(crate) life_guard: LifeGuard,
}

View File

@ -1,81 +1,66 @@
/*! Swap chain management.
## Lifecycle
At the low level, the swap chain is using the new simplified model of gfx-rs.
A swap chain is a separate object that is backend-dependent but shares the index with
the parent surface, which is backend-independent. This ensures a 1:1 correspondence
between them.
`get_next_image()` requests a new image from the surface. It becomes a part of
`TextureViewInner::SwapChain` of the resulted view. The view is registered in the HUB
but not in the device tracker.
The only operation allowed on the view is to be either a color or a resolve attachment.
It can only be used in one command buffer, which needs to be submitted before presenting.
Command buffer tracker knows about the view, but only for the duration of recording.
The view ID is erased from it at the end, so that it's not merged into the device tracker.
When a swapchain view is used in `begin_render_pass()`, we assume the start and end image
layouts purely based on whether or not this view was used in this command buffer before.
It always starts with `Uninitialized` and ends with `Present`, so that no barriers are
needed when we need to actually present it.
In `queue_submit()` we make sure to signal the semaphore whenever we render to a swap
chain view.
In `present()` we return the swap chain image back and wait on the semaphore.
!*/
use crate::{
conv,
device::all_image_stages,
gfx_select,
hub::{GfxBackend, Token},
hub::{GLOBAL, GfxBackend, Token},
resource,
DeviceId,
Extent3d,
Input,
LifeGuard,
Stored,
SwapChainId,
SurfaceId,
TextureId,
TextureViewId,
};
#[cfg(not(feature = "remote"))]
use crate::hub::GLOBAL;
use hal::{
self,
command::CommandBuffer as _,
device::Device as _,
queue::CommandQueue as _,
window::Swapchain as _,
};
use log::{trace, warn};
use parking_lot::Mutex;
use std::{
iter,
mem,
sync::atomic::{AtomicBool, Ordering},
window::PresentationSurface as _,
};
pub type SwapImageEpoch = u64;
#[cfg(not(feature = "remote"))]
use std::marker::PhantomData;
const FRAME_TIMEOUT_MS: u64 = 1000;
#[derive(Debug)]
pub(crate) struct SwapChainLink<E> {
pub swap_chain_id: SwapChainId, //TODO: strongly
pub epoch: E,
pub image_index: hal::window::SwapImageIndex,
}
impl SwapChainLink<Mutex<SwapImageEpoch>> {
pub fn bump_epoch(&self) -> SwapImageEpoch {
let mut epoch = self.epoch.lock();
*epoch += 1;
*epoch
}
}
#[derive(Debug)]
pub(crate) struct Frame<B: hal::Backend> {
pub texture_id: Stored<TextureId>,
pub view_id: Stored<TextureViewId>,
pub fence: B::Fence,
pub sem_available: B::Semaphore,
pub sem_present: B::Semaphore,
pub acquired_epoch: Option<SwapImageEpoch>,
pub need_waiting: AtomicBool,
pub comb: B::CommandBuffer,
}
//TODO: does it need a ref-counted lifetime?
#[derive(Debug)]
pub struct SwapChain<B: hal::Backend> {
//Note: it's only an option because we may need to move it out
// and then put a new swapchain back in.
pub(crate) raw: Option<B::Swapchain>,
pub(crate) surface_id: Stored<SurfaceId>,
pub(crate) life_guard: LifeGuard,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) desc: SwapChainDescriptor,
pub(crate) frames: Vec<Frame<B>>,
pub(crate) acquired: Vec<hal::window::SwapImageIndex>,
pub(crate) sem_available: B::Semaphore,
#[cfg_attr(feature = "remote", allow(dead_code))] //TODO: remove
pub(crate) command_pool: B::CommandPool,
pub(crate) num_frames: hal::window::SwapImageIndex,
pub(crate) acquired_view_id: Option<Stored<TextureViewId>>,
pub(crate) semaphore: B::Semaphore,
}
#[repr(C)]
@ -133,221 +118,119 @@ impl SwapChainDescriptor {
#[repr(C)]
#[derive(Debug)]
pub struct SwapChainOutput {
pub texture_id: TextureId,
pub view_id: TextureViewId,
}
pub fn swap_chain_get_next_texture<B: GfxBackend>(
swap_chain_id: SwapChainId
swap_chain_id: SwapChainId,
view_id_in: Input<TextureViewId>,
) -> SwapChainOutput {
let hub = B::hub();
let mut token = Token::root();
#[cfg(not(feature = "remote"))]
let (mut surface_guard, mut token) = GLOBAL.surfaces.write(&mut token);
let surface = &mut surface_guard[swap_chain_id.to_surface_id()];
let (device_guard, mut token) = hub.devices.read(&mut token);
let (mut swap_chain_guard, _) = hub.swap_chains.write(&mut token);
let swap_chain = &mut swap_chain_guard[swap_chain_id];
let device = &device_guard[swap_chain.device_id.value];
let (mut swap_chain_guard, mut token) = hub.swap_chains.write(&mut token);
let sc = &mut swap_chain_guard[swap_chain_id];
let device = &device_guard[sc.device_id.value];
let image_index = unsafe {
swap_chain
.raw
.as_mut()
.unwrap()
.acquire_image(!0, Some(&swap_chain.sem_available), None)
};
#[cfg(not(feature = "remote"))]
{
if image_index.is_err() {
warn!("acquire_image failed, re-creating");
//TODO: remove this once gfx-rs stops destroying the old swapchain
device.raw.wait_idle().unwrap();
let (mut texture_guard, mut token) = hub.textures.write(&mut token);
let (mut texture_view_guard, _) = hub.texture_views.write(&mut token);
let mut trackers = device.trackers.lock();
let old_raw = swap_chain.raw.take();
let config = swap_chain.desc.to_hal(swap_chain.frames.len() as u32);
let surface = &mut surface_guard[swap_chain.surface_id.value];
let (raw, images) = unsafe {
let suf = B::get_surface_mut(surface);
device
.raw
.create_swapchain(suf, config, old_raw)
.unwrap()
};
swap_chain.raw = Some(raw);
for (frame, image) in swap_chain.frames.iter_mut().zip(images) {
let texture = &mut texture_guard[frame.texture_id.value];
let view_raw = unsafe {
device
.raw
.create_image_view(
&image,
hal::image::ViewKind::D2,
conv::map_texture_format(texture.format),
hal::format::Swizzle::NO,
texture.full_range.clone(),
)
.unwrap()
};
texture.raw = image;
trackers.textures.reset(
frame.texture_id.value,
texture.full_range.clone(),
resource::TextureUsage::UNINITIALIZED,
);
let old_view = mem::replace(&mut texture_view_guard[frame.view_id.value].raw, view_raw);
let (image, _) = {
let suf = B::get_surface_mut(surface);
match unsafe { suf.acquire_image(FRAME_TIMEOUT_MS * 1_000_000) } {
Ok(surface_image) => surface_image,
Err(hal::window::AcquireError::Timeout) => {
panic!("GPU took too much time processing last frames :(");
}
Err(e) => {
log::warn!("acquire_image() failed ({:?}), reconfiguring swapchain", e);
let desc = sc.desc.to_hal(sc.num_frames);
unsafe {
device.raw.destroy_image_view(old_view);
suf
.configure_swapchain(&device.raw, desc)
.unwrap();
suf
.acquire_image(FRAME_TIMEOUT_MS * 1_000_000)
.unwrap()
}
}
}
}
};
let image_index = match image_index {
Ok((index, suboptimal)) => {
if suboptimal.is_some() {
warn!("acquire_image: sub-optimal");
}
index
}
Err(_) => unsafe {
swap_chain
.raw
.as_mut()
.unwrap()
.acquire_image(!0, Some(&swap_chain.sem_available), None)
.unwrap()
.0
let view = resource::TextureView {
inner: resource::TextureViewInner::SwapChain {
image,
source_id: Stored {
value: swap_chain_id,
ref_count: sc.life_guard.ref_count.clone(),
},
},
format: sc.desc.format,
extent: hal::image::Extent {
width: sc.desc.width,
height: sc.desc.height,
depth: 1,
},
samples: 1,
range: hal::image::SubresourceRange {
aspects: hal::format::Aspects::COLOR,
layers: 0 .. 1,
levels: 0 .. 1,
},
life_guard: LifeGuard::new(),
};
let ref_count = view.life_guard.ref_count.clone();
let (view_id, _) = hub.texture_views.new_identity(view_id_in);
hub.texture_views.register(view_id, view, &mut token);
assert_ne!(
swap_chain.acquired.len(),
swap_chain.acquired.capacity(),
"Unable to acquire any more swap chain images before presenting"
);
swap_chain.acquired.push(image_index);
let frame = &mut swap_chain.frames[image_index as usize];
let status = unsafe {
device
.raw
.wait_for_fence(&frame.fence, FRAME_TIMEOUT_MS * 1_000_000)
};
assert_eq!(
status,
Ok(true),
"GPU got stuck on a frame (image {}) :(",
image_index
);
mem::swap(&mut frame.sem_available, &mut swap_chain.sem_available);
frame.need_waiting.store(true, Ordering::Release);
let (texture_guard, _) = hub.textures.read(&mut token);
let frame_epoch = texture_guard[frame.texture_id.value]
.placement
.as_swap_chain()
.bump_epoch();
assert_eq!(
frame.acquired_epoch, None,
"Last swapchain output hasn't been presented"
);
frame.acquired_epoch = Some(frame_epoch);
assert!(sc.acquired_view_id.is_none(), "Swap chain image is already acquired");
sc.acquired_view_id = Some(Stored {
value: view_id,
ref_count,
});
SwapChainOutput {
texture_id: frame.texture_id.value,
view_id: frame.view_id.value,
view_id,
}
}
#[cfg(not(feature = "remote"))]
#[no_mangle]
pub extern "C" fn wgpu_swap_chain_get_next_texture(swap_chain_id: SwapChainId) -> SwapChainOutput {
gfx_select!(swap_chain_id => swap_chain_get_next_texture(swap_chain_id))
gfx_select!(swap_chain_id => swap_chain_get_next_texture(swap_chain_id, PhantomData))
}
pub fn swap_chain_present<B: GfxBackend>(swap_chain_id: SwapChainId) {
let hub = B::hub();
let mut token = Token::root();
let (mut surface_guard, mut token) = GLOBAL.surfaces.write(&mut token);
let surface = &mut surface_guard[swap_chain_id.to_surface_id()];
let (mut device_guard, mut token) = hub.devices.write(&mut token);
let (mut swap_chain_guard, mut token) = hub.swap_chains.write(&mut token);
let swap_chain = &mut swap_chain_guard[swap_chain_id];
let device = &mut device_guard[swap_chain.device_id.value];
let sc = &mut swap_chain_guard[swap_chain_id];
let device = &mut device_guard[sc.device_id.value];
let image_index = swap_chain.acquired.remove(0);
let frame = &mut swap_chain.frames[image_index as usize];
let epoch = frame.acquired_epoch.take();
assert!(
epoch.is_some(),
"Presented frame (image {}) was not acquired",
image_index
);
assert!(
!frame.need_waiting.load(Ordering::Acquire),
"No rendering work has been submitted for the presented frame (image {})",
image_index
);
let (texture_guard, _) = hub.textures.read(&mut token);
let texture = &texture_guard[frame.texture_id.value];
texture.placement.as_swap_chain().bump_epoch();
//TODO: support for swapchain being sampled or read by the shader?
trace!("transit {:?} to present", frame.texture_id.value);
let mut trackers = device.trackers.lock();
let barriers = trackers
.textures
.change_replace(
frame.texture_id.value,
&texture.life_guard.ref_count,
texture.full_range.clone(),
resource::TextureUsage::UNINITIALIZED,
)
.map(|pending| hal::memory::Barrier::Image {
states: conv::map_texture_state(pending.usage.start, hal::format::Aspects::COLOR)
.. (
hal::image::Access::COLOR_ATTACHMENT_WRITE,
hal::image::Layout::Present,
),
target: &texture.raw,
families: None,
range: pending.selector,
});
let view_id = sc.acquired_view_id
.take()
.expect("Swap chain image is not acquired");
let (view, _) = hub.texture_views.unregister(view_id.value, &mut token);
let image = match view.inner {
resource::TextureViewInner::Native { .. } => unreachable!(),
resource::TextureViewInner::SwapChain { image, .. } => image,
};
let err = unsafe {
frame.comb.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT);
frame.comb.pipeline_barrier(
all_image_stages() .. hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
hal::memory::Dependencies::empty(),
barriers,
);
frame.comb.finish();
// now prepare the GPU submission
let submission = hal::queue::Submission {
command_buffers: iter::once(&frame.comb),
wait_semaphores: None,
signal_semaphores: Some(&frame.sem_present),
};
device.raw.reset_fence(&frame.fence).unwrap();
let queue = &mut device.queue_group.queues[0];
queue.submit(submission, Some(&frame.fence));
queue.present(
iter::once((swap_chain.raw.as_ref().unwrap(), image_index)),
iter::once(&frame.sem_present),
queue.present_surface(
B::get_surface_mut(surface),
image,
Some(&sc.semaphore),
)
};
if let Err(e) = err {
warn!("present failed: {:?}", e);
log::warn!("present failed: {:?}", e);
}
}

View File

@ -223,27 +223,6 @@ impl<S: ResourceState> ResourceTracker<S> {
.is_none()
}
/// Resets a resource to the specified usage.
#[cfg(not(feature = "remote"))]
pub fn reset(
&mut self,
id: S::Id,
selector: S::Selector,
default: S::Usage,
) {
let mut state = S::default();
match state.change(id, selector, default, None) {
Ok(()) => (),
Err(_) => unreachable!(),
}
let (index, epoch, backend) = id.unzip();
debug_assert_eq!(backend, self.backend);
let res = self.map.get_mut(&index).unwrap();
assert_eq!(res.epoch, epoch);
res.state = state;
}
/// Query the usage of a resource selector.
///
/// Returns `Some(Usage)` only if this usage is consistent